Facebook Pixel

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:

  1. Remove operation: Remove the topmost element from the pile (if the pile is not empty)
  2. 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 simply nums[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, keeping nums[0] on top
  • 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 (if k < n), which would naturally be on top after removing k elements

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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 (where i < k), we expose nums[i] on top. But we still have k - 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:

  1. The best element from positions [0, k-1) that we can strategically place on top
  2. The element at position k (if it exists) that would naturally be on top after k 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, keeping nums[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:

  1. 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 when k = 1 (empty slice)
  2. Element at index k: nums[k] (when k < n)

    • By removing exactly k elements, we naturally expose nums[k] as the top
    • This doesn't require any add operations

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 Evaluator

Example 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 remove 5, remove 2, then add 5 back. Final: 5 on top.
  • To get 2 on top: Remove 5 (exposing 2), remove 2, add 2 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:

  1. Remove 5 (pile: [2, 8, 3, 1])
  2. Remove 2 (pile: [8, 3, 1])
  3. 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
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

In a binary min heap, the maximum element can be found in:


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More