This was an interview question I had and I was embarrassingly pretty stumped by it. Wanted to know if anyone could think up an answer to it and provide the big O notation for it
I'm pretty sure that the answer is to simply put the *
s right before the biggest digits, so that the largest digit have the biggest impact. For example, if we have
1826456903521651
and we have five multiplications, this would be the answer.
1*82*645*6*903521*651
So the running time would be linear.
Edit: Okay, so this is wrong. We have two counterexamples.
Here's an iterative dynamic programming solution.
As opposed to the recursive version (which should have a similar running time).
The basic idea:
A[position][count]
is the highest number that can be obtained ending at position position
, using count
multiplications.
So:
A[position][count] = max(for i = 0 to position
A[i][count-1] * input.substring(i, position))
Do this for each position and each count, then multiply each of these at the required number of multiplications with the entire remaining string.
Complexity:
Given a string |s|
with m
multiplication operators to be inserted...
O(m|s|2g(s))
where g(s)
is the complexity of multiplication.
Java code:
static long solve(String digits, int multiplications)
{
if (multiplications == 0)
return Long.parseLong(digits);
// Preprocessing - set up substring values
long[][] substrings = new long[digits.length()][digits.length()+1];
for (int i = 0; i < digits.length(); i++)
for (int j = i+1; j <= digits.length(); j++)
substrings[i][j] = Long.parseLong(digits.substring(i, j));
// Calculate multiplications from the left
long[][] A = new long[digits.length()][multiplications+1];
A[0][0] = 1;
for (int i = 1; i < A.length; i++)
{
A[i][0] = substrings[0][i];
for (int j = 1; j < A[0].length; j++)
{
long max = -1;
for (int i2 = 0; i2 < i; i2++)
{
long l = substrings[i2][i];
long prod = l * A[i2][j-1];
max = Math.max(max, prod);
}
A[i][j] = max;
}
}
// Multiply left with right and find maximum
long max = -1;
for (int i = 1; i < A.length; i++)
{
max = Math.max(max, substrings[i][A.length] * A[i][multiplications]);
}
return max;
}
A very basic test:
System.out.println(solve("99287", 1));
System.out.println(solve("99287", 2));
System.out.println(solve("312", 1));
Prints:
86304
72036
62
Yes, it just prints the maximum. It's not too difficult to have it actually print the sums, if required.
The java version, though Python already showed its functional advantage and beat me:
private static class Solution {
BigInteger product;
String expression;
}
private static Solution solve(String digits, int multiplications) {
if (digits.length() < multiplications + 1) {
return null; // No solutions
}
if (multiplications == 0) {
Solution solution = new Solution();
solution.product = new BigInteger(digits);
solution.expression = digits;
return solution;
}
// Position of first '*':
Solution max = null;
for (int i = 1; i < digits.length() - (multiplications - 1); ++i) {
BigInteger n = new BigInteger(digits.substring(0, i));
Solution solutionRest = solve(digits.substring(i), multiplications - 1);
n = n.multiply(solutionRest.product);
if (max == null || n.compareTo(max.product) > 0) {
solutionRest.product = n;
solutionRest.expression = digits.substring(0, i) + "*"
+ solutionRest.expression;
max = solutionRest;
}
}
return max;
}
private static void test(String digits, int multiplications) {
Solution solution = solve(digits, multiplications);
System.out.printf("%s %d -> %s = %s%n", digits, multiplications,
solution.expression, solution.product.toString());
}
public static void main(String[] args) {
test("1826456903521651", 5);
}
Output
1826456903521651 5 -> 182*645*6*903*521*651 = 215719207032420