Find the Maximum Achievable Number
EasyPrompt
Given two integers, num and t. A number x is achievable if it can become equal to num after applying the following operation at most t times:
- Increase or decrease
xby1, and simultaneously increase or decreasenumby1.
Return the maximum possible value of x.
Example 1:
Input: num = 4, t = 1
Output: 6
Explanation:
Apply the following operation once to make the maximum achievable number equal to num:
- Decrease the maximum achievable number by 1, and increase
numby 1.
Example 2:
Input: num = 3, t = 2
Output: 7
Explanation:
Apply the following operation twice to make the maximum achievable number equal to num:
- Decrease the maximum achievable number by 1, and increase
numby 1.
Constraints:
1 <= num, t <= 50
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves checking every possible number x starting from a high value and decreasing. For each x, we simulate the process to see if it can be made equal to num within t operations. The simulation is done using a recursive function that explores all possible outcomes.
Algorithm
- The main idea is to search for the maximum achievable number
xby starting from a high value and iterating downwards. - For each candidate
x, we check if it's possible to makexandnumequal in at mosttsteps. - This check is performed by a recursive function,
isAchievable(currentX, currentNum, stepsLeft), which simulates the process. isAchievablefunction logic:- Base Case 1: If
currentX == currentNum, they are equal, so we returntrue. - Base Case 2: If
stepsLeft == 0and they are not equal, we've run out of operations, so we returnfalse. - Recursive Step: The function explores all four possible operations by making a recursive call for each:
isAchievable(currentX + 1, currentNum + 1, stepsLeft - 1)isAchievable(currentX + 1, currentNum - 1, stepsLeft - 1)isAchievable(currentX - 1, currentNum + 1, stepsLeft - 1)isAchievable(currentX - 1, currentNum - 1, stepsLeft - 1)
- If any of these recursive calls return
true, it means a path to equality exists, and the function returnstrue. Otherwise, it returnsfalse.
- Base Case 1: If
- The first value of
x(iterating downwards) for whichisAchievablereturnstrueis the maximum possible value.
Walkthrough
We want to find the maximum achievable x. A simple strategy is to start checking from a large number and go downwards. The first number we find that is "achievable" will be our answer.
A safe upper bound to start from can be derived from the constraints. Since num <= 50 and t <= 50, num + 2*t is at most 50 + 100 = 150. We can start our search from a number like 200.
The core of this approach is the isAchievable(current_x, current_num, steps_left) function. This function checks if current_x and current_num can be made equal using steps_left operations.
class Solution { public int theMaximumAchievableX(int num, int t) { // Start checking from a reasonably high number downwards. // num + 2*t is the actual answer, so starting there is efficient. // For a true brute-force, we might start from a hardcoded limit like 200. for (int x = num + 2 * t; x >= 1; x--) { if (isAchievable(x, num, t)) { return x; } } return -1; // Should not be reached } private boolean isAchievable(long currentX, long currentNum, int stepsLeft) { if (currentX == currentNum) { return true; } if (stepsLeft == 0) { return false; } // Explore all 4 possible operations if (isAchievable(currentX + 1, currentNum + 1, stepsLeft - 1)) return true; if (isAchievable(currentX + 1, currentNum - 1, stepsLeft - 1)) return true; if (isAchievable(currentX - 1, currentNum + 1, stepsLeft - 1)) return true; if (isAchievable(currentX - 1, currentNum - 1, stepsLeft - 1)) return true; return false; }}Complexity
Time
O(4^t) The `isAchievable` function has a branching factor of 4 and a maximum depth of `t`. This leads to an exponential number of calls, making the complexity `O(4^t)`. The outer loop for `x` is negligible in comparison.
Space
O(t) The space complexity is determined by the maximum depth of the recursion stack, which is `t`.
Trade-offs
Pros
Simple to conceptualize as it directly models the problem statement.
Cons
Extremely inefficient due to its exponential time complexity.
Will result in a 'Time Limit Exceeded' error for the given constraints.
This approach improves upon the brute-force simulation by using memoization (a form of dynamic programming) to avoid recomputing results for the same subproblems. The state of the recursion can be simplified by focusing on the difference between the two numbers, making memoization effective.
Algorithm
- This approach builds upon the previous one by optimizing the recursive simulation with memoization to avoid redundant computations.
- The key observation is that the state of the simulation can be defined by the difference between
xandnum, rather than their absolute values. - Let
diff = currentX - currentNum. Each operation changesdiffby0,+2, or-2. - We use a memoization table (e.g., a HashMap or a 2D array) to store the results of
isAchievable(diff, stepsLeft). isAchievablefunction with memoization:- Base Case 1: If
diff == 0, returntrue. - Base Case 2: If
stepsLeft == 0, returnfalse. - Memoization Check: Before computing, check if the result for the state
(diff, stepsLeft)is already in the memo table. If so, return the stored value. - Recursive Step: Recursively call the function for the three possible outcomes of the difference:
isAchievable(diff, stepsLeft - 1)isAchievable(diff + 2, stepsLeft - 1)isAchievable(diff - 2, stepsLeft - 1)
- Store the result in the memo table before returning.
- Base Case 1: If
Walkthrough
The naive recursive simulation has many overlapping subproblems. For instance, the state (x=10, num=8, steps=5) might be reached through different sequences of operations. We can optimize this by caching the results.
The state of a subproblem is defined by (currentX, currentNum, stepsLeft). However, the absolute values can grow large. A better state representation is (diff, stepsLeft), where diff = currentX - currentNum. This significantly reduces the state space.
import java.util.HashMap;import java.util.Map; class Solution { public int theMaximumAchievableX(int num, int t) { // The outer loop is kept for the brute-force structure, but it will // find the answer on the first try if we start from num + 2*t. for (int x = num + 2 * t; x >= 1; x--) { Map<Long, Map<Integer, Boolean>> memo = new HashMap<>(); if (isAchievable(x - (long)num, t, memo)) { return x; } } return -1; } private boolean isAchievable(long diff, int stepsLeft, Map<Long, Map<Integer, Boolean>> memo) { if (diff == 0) { return true; } if (stepsLeft == 0) { return false; } if (memo.containsKey(diff) && memo.get(diff).containsKey(stepsLeft)) { return memo.get(diff).get(stepsLeft); } // Explore possible changes to the difference boolean possible = isAchievable(diff, stepsLeft - 1, memo) || isAchievable(diff + 2, stepsLeft - 1, memo) || isAchievable(diff - 2, stepsLeft - 1, memo); memo.computeIfAbsent(diff, k -> new HashMap<>()).put(stepsLeft, possible); return possible; }}Complexity
Time
O(t^2) With memoization, each state `(diff, stepsLeft)` is computed only once. The number of states is `O(t^2)`, and each computation takes constant time. Thus, the check for a given `x` is `O(t^2)`.
Space
O(t^2) The space is used for the memoization table. The number of `stepsLeft` is `t`. The range of `diff` values explored is also proportional to `t`, leading to `O(t^2)` states.
Trade-offs
Pros
Significantly more efficient than the naive recursive approach.
Passes within the time limits for the given constraints.
Cons
More complex to implement than the direct mathematical formula.
Still performs more computation than necessary compared to the optimal O(1) solution.
The most efficient approach is to use a direct mathematical insight. By analyzing how the difference between x and num changes with each operation, we can derive a simple formula for the maximum achievable x.
Algorithm
- Analyze the effect of a single operation on the difference
d = x - num.(x++, num++)or(x--, num--):dis unchanged.(x++, num--):dincreases by 2.(x--, num++):ddecreases by 2.
- In one operation, the distance
|x - num|can be reduced by at most 2. - To make
xandnumequal intoperations, the initial distance|x - num|must be coverable withintsteps. - The maximum distance that can be covered in
toperations is2 * t(by reducing the distance by 2 in every step). - Therefore, the initial distance must satisfy
|x - num| <= 2 * t. - We want to find the maximum possible
x. This means we want to maximizexsubject to the constraintx - num <= 2 * t. - This gives the upper bound
x <= num + 2 * t. - The maximum value for
xis thusnum + 2 * t. - This value is achievable: start with
x = num + 2t. Apply the operation(x--, num++)forttimes.xbecomes(num + 2t) - t = num + t.numbecomesnum + t. They become equal.
Walkthrough
Let's analyze the effect of a single operation on the difference d = x - num. An operation can change d by 0, +2, or -2. This means that with each operation, we can change the difference by an even number.
For x to be achievable, it must be possible to make it equal to num after some number of operations, say k (where k <= t). This means their final difference must be zero. To bridge an initial difference of x - num, the total change must be num - x.
The most effective way to make x and num meet is to move them towards each other. If x > num, we use the operation (x--, num++). This reduces their difference by 2. After t such operations, the total reduction in difference is 2 * t.
This implies that the initial difference |x - num| can be at most 2 * t. To find the maximum possible x, we assume x is larger than num and set their difference to the maximum possible value:
x - num = 2 * t
Solving for x, we get:
x = num + 2 * t
This gives us a direct formula to calculate the answer.
class Solution { public int theMaximumAchievableX(int num, int t) { // Each operation can bring x and num closer by at most 2. // To cover the maximum initial distance in t steps, that distance is 2*t. // To maximize x, we assume x > num, so the initial difference is x - num. // Therefore, the maximum possible x is num + 2*t. return num + 2 * t; }}Complexity
Time
O(1) The solution involves a single arithmetic calculation, which takes constant time.
Space
O(1) No extra space is used that depends on the input size. The computation is done with a few variables.
Trade-offs
Pros
Extremely efficient with constant time and space complexity.
Very simple and concise to implement.
Cons
Requires a mathematical insight that might not be immediately obvious.
Solutions
Solution
class Solution {public int theMaximumAchievableX(int num, int t) { return num + t * 2; }}class Solution {public: int theMaximumAchievableX(int num, int t) { return num + t * 2; }};class Solution: def theMaximumAchievableX( self, num: int, t: int) -> int: return num + t * 2Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.