For example, you are given the source
1234 and the target
24. The task is to use the standard arithmetic operators +-/*
placed within source
, without changing the order of the digits of source
to create target
. In this example the solutions are:
1 * 2 * 3 * 4 = 24 = target
12 + 3 * 4 = 24 = target
Another example:
target=346
source=8675309
# solution
867 - 530 + 9 = 346
My question is what data structures and algorithms should I be thinking about for this problem? I've written a solution to this using Python, but it is terribly naive and brute forces the problem. It creates all possible splits in source
, and then creates all possible expressions by interleaving every combination of +-\*
within the split of source.
It takes a LONG time to find this solution:
source=314159265358
target=27182
# solution
3141 * 5 / 9 * 26 / 5 * 3 - 5 * 8
I believe the complexity is O(2^n)
, where n
is the number of digits in source
. After each digit you can split or not.
Code below (note it errors if source
has a 0
):
#!/usr/bin/env python
from __future__ import print_function
from itertools import combinations
from itertools import product
from sys import argv
def split_number(s):
""" takes input string number and splits it into strings of separate digits """
return [_ for _ in s]
def partition_list(aList, indices):
""" split a list into parts, splitting at the indices """
indices = list(indices)
return [aList[a:b] for a, b in zip([0] + indices, indices+[None])]
def create_index_splits(list_len, n):
""" returns a list of all places to create splits to create n splits in a
list of len list_len """
return list(combinations(range(1, list_len), n))
def generate_expression(l, operators):
""" takes a list of list l and a sequence of operators and creates an
expression of the intreleaved list and operators """
expression = [item for pair in zip(l, operators) for item in pair]
# interleave operands and operators
return ' '.join(expression + [l[-1]])
def generate_expressions(l):
"""generate all possible combinations of digits splits and operators """
l = convert_list_ints_to_list_str(l)
operators = '+/*-'
# cartesian product of operators
operator_combinations = product(operators, repeat=len(l) - 1)
return [generate_expression(l, _) for _ in operator_combinations]
def convert_list_ints_to_list_str(l):
"""converst list of lists of digits to list of numbers """
return [''.join(map(str, _)) for _ in l]
def find_solutions(a, b):
l = split_number(a)
index_splits = [create_index_splits(len(l), _) for _ in range(1, len(l))]
index_splits = [i for j in index_splits for i in j]
m = [partition_list(l, _) for _ in index_splits]
b = int(b)
expressions = list([generate_expressions(_) for _ in m])
expressions = [i for j in expressions for i in j]
return [_ for _ in expressions if eval(_) == b]
def main():
try:
a = argv[1]
b = argv[2]
except (ValueError, IndexError):
print("invalid args")
[print(_) for _ in find_solutions(a, b)]
if __name__ == '__main__':
main()
To run it do python thisfile.py [source] [target]