Approaching a problem in the standard way, or the way the problem asks you is not always the optimal solution. Sometimes it is best for us to think out of the box. Just like solving a maze, sometimes we find it easier by connecting the start and finish when we actually start at the finish point.
LeetCode #991
There is a broken calculator that has the integer
startValue
on its display initially. In one operation, you can:
- multiply the number on display by
2
, or- subtract
1
from the number on display.Given two integers
startValue
andtarget
, return the minimum number of operations needed to displaytarget
on the calculator.
The first approach that comes to mind is to use recursion and try to approach the target by the two operations above. To decide which to use, we simply check that which operation brings us closer to the target.
class Solution {
public:
int brokenCalc(int startValue, int target) {
if(startValue == target)
return 0;
else if(startValue >= target / 2.0)
return 1 + brokenCalc(startValue - 1, target);
return 1 + brokenCalc(2 * startValue, target);
}
};
However, not only does the code above would result in a TLE, it does not yield the optimal result. Take (5, 8) for an example:
When we first decide which operation to use, we would choose the times 2 one and then just complete two more subtractions to get the 8 we want, totaling in 3 operations. However, if we were to first subtract 1 from 5 and then multiply the number by 2, we would get the 8 with 1 less step. Now, this raises a question, is the way we choose which operation to use actually optimal?
Obviously, the answer is no, and there is no feasible way of finding out the best solution if we are approaching the problem in this way.
The way we approach this is backward. We have to make our result as close to our starting value. Since it is reversed, the two operations will be:
1) Divide the target by 2
2) Add 1 to the target
All we need to do is keep on dividing the target until it is smaller or equal to the starting value. If the target is odd, we will add one first and then carry on with the division. Finally, we will just complete the result by continuously adding one to the target until they are equal:
class Solution {
public:
int brokenCalc(int startValue, int target) {
int count = 0;
while(target > startValue){
if(target % 2)
target++;
else
target /= 2;
count ++;
}
return count + startValue - target;
}
};