def longest_sequence_from_one(xs): if not xs: return 0 if not xs[0] == 1: return 0 length = 1 for i in range(len(xs) - 1): if xs[i] + 1 == xs[i + 1]: length += 1 else: break return length def choose(xs, n): if not xs or n == 0: return [[]] if len(xs) == n: return [xs] rs = [] x = xs[0] for r in choose(xs[1:], n - 1): rs.append([x] + r) for r in choose(xs[1:], n): rs.append(r) return rs def insert_all(x, ys): return [ys[:i] + [x] + ys[i:] for i in range(len(ys) + 1)] def permutations(xs): if not xs: return [[]] r = [] x = xs[0] for ps in permutations(xs[1:]): r += insert_all(x, ps) return r def subset_pairs(xs): """ Returns all pairs of non-empty subsets. """ assert(len(xs) >= 2) return [(xs[:i], xs[i:]) for i in range(1, len(xs))] def all_ops(a, b): """ Combines the two arguments with the four basic arithmetic operations. """ r = [a + b, a - b, a * b] if b != 0: r.append(a / b) return r def all_ops_list(xs): """ Combines the arguments with all arithmetic operations with all forms of bracketing. It does not permutate the order of the args. """ if len(xs) == 1: return xs elif len(xs) == 2: return all_ops(*xs) rs = [] for ss1, ss2 in subset_pairs(xs): cs = [c for a in all_ops_list(ss1) for b in all_ops_list(ss2) for c in all_ops(a, b)] rs += cs return rs def get_sequence_lenght_four_digits(ds): ps = permutations(ds) rs = [] for p in ps: rs += all_ops_list(p) rs = [r for r in rs if int(r) == r and r >= 1] rs = sorted(list(set(rs))) return longest_sequence_from_one(rs) def euler_093(): cs = choose(list(range(10)), 4) max_seq, max_len = [], 0 for c in cs: l = get_sequence_lenght_four_digits(c) if l > max_len: max_len = l max_seq = c return int("".join(map(str, max_seq))) if __name__ == "__main__": solution = euler_093() print("e093.py: " + str(solution)) assert(solution == 1258)