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]