2202. Maximize the Topmost Element After K Moves
Problem Description
You have a pile of integers represented as an array nums
, where nums[0]
is the top element of the pile. You can perform exactly k
moves, where each move is one of two operations:
- Remove operation: Remove the topmost element from the pile (if the pile is not empty)
- Add operation: Put back any previously removed element onto the pile, making it the new topmost element
Your goal is to find the maximum possible value of the topmost element after performing exactly k
moves. If the pile becomes empty after k
moves and cannot have any element on top, return -1
.
The solution handles several key cases:
- When
k = 0
: No moves can be made, so the answer is simplynums[0]
- When the array has only one element (
n = 1
):- If
k
is odd, you must remove the only element and cannot put it back, resulting in-1
- If
k
is even, you can remove and add back the element repeatedly, keepingnums[0]
on top
- If
- For general cases: The maximum achievable value is either:
- The maximum among the first
k-1
elements (which can be exposed by removing elements above them, then potentially added back on top) - The element at index
k
(ifk < n
), which would naturally be on top after removingk
elements
- The maximum among the first
The algorithm efficiently finds the maximum by checking elements within reach of k
moves, considering that we can strategically remove elements to expose larger values and potentially place them back on top.
Intuition
The key insight is understanding what elements we can potentially place on top after exactly k
moves.
Let's think about what happens with different move sequences:
- If we remove
i
elements (wherei < k
), we exposenums[i]
on top. But we still havek - i
moves left. - Since we must use exactly
k
moves, we need to "waste" the remaining moves. We can do this by repeatedly removing and adding back elements. - This means any element in the first
k-1
positions can potentially end up on top! We can remove elements to expose it, pick it up, then use remaining moves to shuffle elements, finally placing our chosen element back on top.
Why specifically the first k-1
elements? Because if we remove k-1
elements, we have 1 move left to add back any of those removed elements. This gives us maximum flexibility.
Additionally, if k < n
, we can simply remove the first k
elements, which naturally leaves nums[k]
on top without any add operations.
Special cases emerge from this logic:
- With only one element and odd
k
: We're forced to end with a remove operation (since remove and add alternate), leaving the pile empty. - With only one element and even
k
: We can pair up moves (remove-add cycles), keeping the element on top.
The solution elegantly captures this by taking the maximum of:
- The best element from positions
[0, k-1)
that we can strategically place on top - The element at position
k
(if it exists) that would naturally be on top afterk
removals
This greedy approach works because we want the maximum value, and we have the flexibility to arrange our moves to achieve it.
Learn more about Greedy patterns.
Solution Approach
The implementation follows a case-by-case analysis based on the insights from our intuition:
Base Case - No moves (k = 0
):
if k == 0: return nums[0]
When no moves are allowed, the topmost element remains nums[0]
.
Special Case - Single element array (n = 1
):
if n == 1: if k % 2: return -1 return nums[0]
- If
k
is odd, we must end with a remove operation, leaving an empty pile β return-1
- If
k
is even, we can perform remove-add cycles, keepingnums[0]
on top
General Case - Multiple elements:
ans = max(nums[: k - 1], default=-1)
if k < n:
ans = max(ans, nums[k])
return ans
This handles two scenarios:
-
First
k-1
elements:max(nums[: k - 1], default=-1)
- We can remove up to
k-1
elements to expose any of them - Then use the last move to add back the maximum element among them
- The
default=-1
handles the edge case whenk = 1
(empty slice)
- We can remove up to
-
Element at index
k
:nums[k]
(whenk < n
)- By removing exactly
k
elements, we naturally exposenums[k]
as the top - This doesn't require any add operations
- By removing exactly
The final answer is the maximum of these two possibilities.
Time Complexity: O(min(k, n))
- We examine at most k
elements from the array
Space Complexity: O(1)
- Only using a constant amount of extra space
The elegance of this solution lies in recognizing that we only need to consider elements within reach of our k
moves, and the maximum value among these reachable elements will be our answer.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example with nums = [5, 2, 8, 3, 1]
and k = 3
.
Step 1: Identify what elements we can potentially have on top
With k = 3
moves, we have two strategies:
- Strategy A: Remove some elements, then use remaining moves to place a desired element on top
- Strategy B: Remove exactly
k
elements to expose what's underneath
Step 2: Explore Strategy A - First k-1
elements
We can access the first k-1 = 2
elements: [5, 2]
- To get
5
on top: It's already there! But we need exactly 3 moves. We could remove5
, remove2
, then add5
back. Final:5
on top. - To get
2
on top: Remove5
(exposing2
), remove2
, add2
back. Final:2
on top.
Maximum from this strategy: max([5, 2]) = 5
Step 3: Explore Strategy B - Element at index k
If we remove exactly 3 elements (5
, 2
, 8
), we expose nums[3] = 3
on top.
- Move 1: Remove
5
β pile is[2, 8, 3, 1]
- Move 2: Remove
2
β pile is[8, 3, 1]
- Move 3: Remove
8
β pile is[3, 1]
Final: 3
on top.
Step 4: Compare both strategies
- Strategy A maximum:
5
- Strategy B result:
3
The answer is max(5, 3) = 5
.
Verification: We can achieve this by:
- Remove
5
(pile:[2, 8, 3, 1]
) - Remove
2
(pile:[8, 3, 1]
) - Add
5
back (pile:[5, 8, 3, 1]
)
After exactly 3 moves, we have 5
on top, which matches our answer!
Solution Implementation
1class Solution:
2 def maximumTop(self, nums: List[int], k: int) -> int:
3 # If no operations allowed, return the first element
4 if k == 0:
5 return nums[0]
6
7 # Get the length of the array
8 n = len(nums)
9
10 # Special case: single element array
11 if n == 1:
12 # With odd k, we must remove the only element (can't put it back)
13 if k % 2 == 1:
14 return -1
15 # With even k, we can remove and add back the same element
16 return nums[0]
17
18 # Find the maximum among the first (k-1) elements
19 # These elements can be removed and one of them placed back on top
20 max_from_removed = max(nums[:k - 1], default=-1)
21
22 # If k < n, we can also remove k elements and leave nums[k] on top
23 if k < n:
24 max_from_removed = max(max_from_removed, nums[k])
25
26 return max_from_removed
27
1class Solution {
2 public int maximumTop(int[] nums, int k) {
3 // If no operations are allowed, return the top element
4 if (k == 0) {
5 return nums[0];
6 }
7
8 int n = nums.length;
9
10 // Special case: single element array
11 if (n == 1) {
12 // With odd k, we always end up with empty pile (remove-add-remove pattern)
13 if (k % 2 == 1) {
14 return -1;
15 }
16 // With even k, we can put the element back on top
17 return nums[0];
18 }
19
20 // Track the maximum element we can place on top
21 int maxElement = -1;
22
23 // Option 1: Remove (k-1) elements and put back the maximum among them
24 // We can access at most (k-1) elements or all n elements, whichever is smaller
25 for (int i = 0; i < Math.min(k - 1, n); i++) {
26 maxElement = Math.max(maxElement, nums[i]);
27 }
28
29 // Option 2: Remove exactly k elements, exposing the element at index k
30 // This is only possible if k < n
31 if (k < n) {
32 maxElement = Math.max(maxElement, nums[k]);
33 }
34
35 return maxElement;
36 }
37}
38
1class Solution {
2public:
3 int maximumTop(vector<int>& nums, int k) {
4 // If no operations allowed, return the top element
5 if (k == 0) {
6 return nums[0];
7 }
8
9 int n = nums.size();
10
11 // Special case: single element array
12 if (n == 1) {
13 // With odd k, we'll always end with empty pile
14 if (k % 2 == 1) {
15 return -1;
16 }
17 // With even k, we can put the element back
18 return nums[0];
19 }
20
21 // Find the maximum element we can place on top
22 int maxElement = -1;
23
24 // We can remove and add back any of the first (k-1) elements
25 // This uses k-1 operations to remove them, and 1 operation to add back the max
26 for (int i = 0; i < min(k - 1, n); ++i) {
27 maxElement = max(maxElement, nums[i]);
28 }
29
30 // If k < n, we can also just remove k elements to expose nums[k]
31 if (k < n) {
32 maxElement = max(maxElement, nums[k]);
33 }
34
35 return maxElement;
36 }
37};
38
1function maximumTop(nums: number[], k: number): number {
2 // If no operations allowed, return the top element
3 if (k === 0) {
4 return nums[0];
5 }
6
7 const n = nums.length;
8
9 // Special case: single element array
10 if (n === 1) {
11 // With odd k, we'll always end with empty pile
12 if (k % 2 === 1) {
13 return -1;
14 }
15 // With even k, we can put the element back
16 return nums[0];
17 }
18
19 // Find the maximum element we can place on top
20 let maxElement = -1;
21
22 // We can remove and add back any of the first (k-1) elements
23 // This uses k-1 operations to remove them, and 1 operation to add back the max
24 for (let i = 0; i < Math.min(k - 1, n); i++) {
25 maxElement = Math.max(maxElement, nums[i]);
26 }
27
28 // If k < n, we can also just remove k elements to expose nums[k]
29 if (k < n) {
30 maxElement = Math.max(maxElement, nums[k]);
31 }
32
33 return maxElement;
34}
35
Time and Space Complexity
Time Complexity: O(k)
where k
is the number of operations allowed.
The time complexity is determined by the line ans = max(nums[: k - 1], default=-1)
, which creates a slice of the array containing up to k - 1
elements and finds the maximum among them. The slicing operation takes O(min(k - 1, n))
time, and finding the maximum takes O(min(k - 1, n))
time as well. Since we typically consider k
as the parameter (and in the worst case k - 1
could be as large as n - 1
), the overall time complexity is O(k)
.
All other operations in the code, including the comparisons and single element access nums[k]
, take O(1)
time.
Space Complexity: O(k)
where k
is the number of operations allowed.
The space complexity is dominated by the slicing operation nums[: k - 1]
, which creates a new list containing up to k - 1
elements. This requires O(min(k - 1, n))
additional space. In the worst case, this is O(k)
space.
The remaining variables (ans
, n
) use only O(1)
additional space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Mishandling the k = 1 Case with Multiple Elements
A common mistake is not properly handling when k = 1
and the array has multiple elements. When slicing nums[:k-1]
with k = 1
, this becomes nums[:0]
, which is an empty slice.
Incorrect approach:
# This would crash without the default parameter
max_from_removed = max(nums[:k - 1]) # Error when k = 1!
Correct approach:
# Use default=-1 to handle empty slice
max_from_removed = max(nums[:k - 1], default=-1)
2. Incorrectly Assuming We Must Use All k Moves
Another pitfall is thinking we need to maximize the value while using exactly k
operations, rather than after performing exactly k
operations. The key insight is that we can strategically use remove and add operations to position the maximum element on top.
Wrong thinking: "I must remove k elements, so the answer is always nums[k]
"
Correct understanding: We can remove elements to find the maximum, then use our remaining moves to place it on top (as long as we use exactly k total moves).
3. Off-by-One Error in Range Calculation
A frequent error occurs when determining which elements are reachable:
Incorrect:
# This would include one too many elements
max_from_removed = max(nums[:k], default=-1) # Wrong! Includes k elements
Correct:
# We can remove up to k-1 elements and use the last move to add back
max_from_removed = max(nums[:k - 1], default=-1)
The reason is that if we want to place an element back on top, we need to save one operation for the "add" action, so we can only remove up to k-1
elements.
4. Not Considering the Element at Position k
When k < n
, forgetting that we can simply remove k
elements to expose nums[k]
without any add operations:
Incomplete solution:
# Only considers elements that can be removed and added back
return max(nums[:k - 1], default=-1) # Misses nums[k] possibility
Complete solution:
ans = max(nums[:k - 1], default=-1)
if k < n:
ans = max(ans, nums[k]) # Also consider the element naturally exposed
return ans
5. Single Element Array Edge Case with Even/Odd k
Failing to recognize that with a single-element array, the parity of k
determines whether we can have an element on top:
Wrong approach:
if n == 1: return nums[0] # Incorrect! Doesn't consider k's parity
Correct approach:
if n == 1: if k % 2 == 1: # Odd k means we end with removal return -1 return nums[0] # Even k means we can cycle remove-add
In a binary min heap, the maximum element can be found in:
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!