Taro Logo

Minimum Moves to Reach Target Score

Medium
Amazon logo
Amazon
1 view
Topics:
Greedy AlgorithmsBit Manipulation

You are playing a game with integers. You start with the integer 1 and you want to reach the integer target.

In one move, you can either:

  1. Increment the current integer by one (i.e., x = x + 1).
  2. Double the current integer (i.e., x = 2 * x).

You can use the increment operation any number of times, however, you can only use the double operation at most maxDoubles times.

Given the two integers target and maxDoubles, return the minimum number of moves needed to reach target starting with 1.

Example 1:

Input: target = 5, maxDoubles = 0
Output: 4
Explanation: Keep incrementing by 1 until you reach target.

Example 2:

Input: target = 19, maxDoubles = 2
Output: 7
Explanation: Initially, x = 1
Increment 3 times so x = 4
Double once so x = 8
Increment once so x = 9
Double again so x = 18
Increment once so x = 19

Example 3:

Input: target = 10, maxDoubles = 4
Output: 4
Explanation:  Initially, x = 1
Increment once so x = 2
Double once so x = 4
Increment once so x = 5
Double again so x = 10

Solution


Naive Approach

The most straightforward approach is to simply increment from 1 until we reach the target. If maxDoubles is greater than 0, we can explore doubling at each step and then recursively check the number of operations required to reach target.

This brute-force approach will explore all possible paths of incrementing and doubling (up to maxDoubles doublings) until we find the minimum number of operations.

However, it can be very inefficient, especially for large targets and maxDoubles, leading to a time limit exceeded error.

Optimal Approach

Instead of working forwards from 1 to the target, let's work backward from the target to 1.

If the target is even, we can divide it by 2 if we have any doubles available. If we don't have any doubles available or if the target is odd, we decrement by 1.

We repeat this process until the target becomes 1. This approach ensures that we use doubling operations as much as possible when the target is even, thereby minimizing the overall number of operations.

Here's a breakdown:

  1. Initialization: Initialize moves to 0.
  2. Iteration:
    • While target is greater than 1:
      • If maxDoubles is greater than 0 and target is even:
        • Divide target by 2.
        • Decrement maxDoubles.
        • Increment moves.
      • Else:
        • If maxDoubles is 0, increment target until it becomes odd to use decrement efficiently.
        • Decrement target by 1.
        • Increment moves.
  3. Return: Return moves.

Edge Cases

  • If target is 1, the number of moves is 0.
  • If maxDoubles is 0, the number of moves is target - 1.

Code Implementation (Java)

class Solution {
    public int minMoves(int target, int maxDoubles) {
        int moves = 0;
        while (target > 1) {
            if (maxDoubles > 0 && target % 2 == 0) {
                target /= 2;
                maxDoubles--;
                moves++;
            } else {
                if (maxDoubles == 0) {
                   return moves + target -1;
                }
                target--;
                moves++;
            }
        }
        return moves;
    }
}

Time and Space Complexity

  • Time Complexity: O(target) in the worst case (when maxDoubles is 0 or very small compared to the number of decrements required), and O(log target) in the best case (when we can divide target multiple times and maxDoubles is large enough). In any case, it's significantly better than exponential time complexity of brute force.
  • Space Complexity: O(1) - The algorithm uses constant extra space.