Tim Varley Logo
Tim Varley Principal AI Engineer and Tech Leader
Problem #93 medium

Arithmetic expressions

By using each of the digits from the set, {1,2,3,4}\{1, 2, 3, 4\}, exactly once, and making use of the four arithmetic operations (+,,×,/+, -, \times, /) and brackets/parentheses, it is possible to form different positive integer targets.

For example,

8=(4×(1+3))/28 = (4 \times (1 + 3)) / 2

14=4×(3+1/2)14 = 4 \times (3 + 1 / 2)

19=4×(2+3)119 = 4 \times (2 + 3) - 1

36=3×4×(2+1)36 = 3 \times 4 \times (2 + 1)

Note that concatenations of the digits, like 12+3412 + 34, are not allowed.

Using the set, {1,2,3,4}\{1, 2, 3, 4\}, it is possible to obtain thirty-one different target numbers of which 3636 is the maximum, and each of the numbers 11 to 2828 can be obtained before encountering the first non-expressible number.

Find the set of four distinct digits, a<b<c<da \lt b \lt c \lt d, for which the longest set of consecutive positive integers, 11 to nn, can be obtained, giving your answer as a string: abcd.

View on Project Euler

Implementations

cpp
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
std::set<double> evaluate_rec(const std::vector<double>& nums) {
int n = nums.size();
std::set<double> results;
if (n == 1) {
results.insert(nums[0]);
return results;
}
// try all ways to split
for (int i = 1; i < n; ++i) {
auto left = std::vector<double>(nums.begin(), nums.begin() + i);
auto right = std::vector<double>(nums.begin() + i, nums.end());
auto left_vals = evaluate_rec(left);
auto right_vals = evaluate_rec(right);
for (double lv : left_vals) {
for (double rv : right_vals) {
results.insert(lv + rv);
results.insert(lv - rv);
results.insert(lv * rv);
if (rv != 0) results.insert(lv / rv);
}
}
}
return results;
}
std::set<int> evaluate(const std::vector<double>& nums) {
auto doubles = evaluate_rec(nums);
std::set<int> ints;
for (double d : doubles) {
if (d > 0 && d == (int)d) ints.insert((int)d);
}
return ints;
}
long long arithmetic_expressions() {
std::vector<int> digits = {1,2,3,4,5,6,7,8,9};
int max_n = 0;
std::string best_set;
for (int a = 0; a < 9; ++a) {
for (int b = a + 1; b < 9; ++b) {
for (int c = b + 1; c < 9; ++c) {
for (int d = c + 1; d < 9; ++d) {
std::vector<int> set = {digits[a], digits[b], digits[c], digits[d]};
std::set<int> values;
// generate all permutations of set
do {
std::vector<double> nums(set.begin(), set.end());
auto res = evaluate(nums);
values.insert(res.begin(), res.end());
} while (std::next_permutation(set.begin(), set.end()));
// find longest consecutive from 1
int n = 0;
while (values.count(n + 1)) n++;
if (n > max_n) {
max_n = n;
best_set = std::to_string(set[0]) + std::to_string(set[1]) + std::to_string(set[2]) + std::to_string(set[3]);
}
}
}
}
}
return std::stoi(best_set);
}

Solution Notes

Mathematical Background

The problem involves finding the optimal set of four distinct digits that can generate the longest sequence of consecutive positive integers starting from 1 using basic arithmetic operations (+, -, *, /) and parentheses.

Algorithm Analysis

The solution uses recursive expression evaluation to generate all possible values from digit permutations, then finds the set maximizing consecutive integers from 1.

Performance

Varies by language: ~500ms in C++/Go/Java/JavaScript, ~1000ms in Python/Rust on modern hardware.

Key Insights

  • Recursive evaluation of all possible expression trees
  • Permutation generation for different digit orders
  • Finding maximal consecutive sequences starting from 1

Educational Value

Demonstrates combinatorial problem solving, recursive algorithms, and optimization techniques in multiple programming languages.

Problem #93 is taken from Project Euler and licensed under CC BY-NC-SA 4.0.