-1

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]

Idr
  • 107
  • 3

1 Answers1

0

I doubt that there is a solution that is not exponential in the number of digits. It seems similar to The subset sum problem, but with an even larger search space. In other words, you can't do much better than an exhaustive search.

kevin cline
  • 33,608
  • 3
  • 71
  • 142