Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

2202. Maximize the Topmost Element After K Moves - Leetcode Solution

Problem Description

You are given an integer array nums representing a stack, where nums[0] is the topmost element. You are also given an integer k representing the maximum number of moves you can make. In each move, you can either:

  • Remove the topmost element of the stack (if the stack is not empty).
  • Put back any one of the previously removed elements (if you have any).

You must make exactly k moves. After k moves, if the stack is not empty, you want to maximize the value of the topmost element. If the stack is empty after k moves, return -1.

Constraints:

  • You cannot reuse elements that are not yet removed.
  • You must make exactly k moves.
  • Only one element can be put back at a time.
Goal: Maximize the value of the topmost element after k moves, or return -1 if impossible.

Thought Process

At first glance, it seems you could try all possible sequences of removes and puts, but this approach quickly becomes infeasible for large k or large stacks. Instead, we look for patterns and constraints:

  • If you remove all elements, the stack is empty, which is not allowed unless k equals the stack size.
  • Since you can only put back previously removed elements, you are always limited to the first k elements of the stack (since you can't remove more than k elements in k moves).
  • We want to maximize the topmost element after k moves, so we need to consider which element can be placed on top after exactly k moves.
  • Brute-force would try every combination of removes and puts, but we need an optimized way to reason about which elements can be on top.

The key insight is to recognize that you can only ever put back elements you've removed, and you can't put back more than one per move. The number of elements you can remove is at most k. The optimal strategy is to consider the largest possible element among the first k-1 elements (since you can remove and put back any of them), and possibly the k-th element if you just keep removing.

Solution Approach

Let's break the solution into clear steps:

  1. Edge Case 1: If k == 0, you can't do anything, so the answer is just nums[0].
  2. Edge Case 2: If k == 1, you can only remove the top element or leave it. If the stack has only one element, removing it leaves the stack empty, so return -1. Otherwise, after one move, the top is nums[1].
  3. General Case:
    • If k is less than the length of nums:
      • You can remove up to k-1 elements and put back any one of them as the top, or just remove k elements and leave the k-th element as the new top.
      • So, the possible topmost elements after k moves are:
        • Any of the first k-1 elements (if you remove and put back one of them), or
        • The k-th element (nums[k]) if you just keep removing.
        The answer is the maximum among these.
    • If k is greater than or equal to the length of nums:
      • You can remove all elements and put back any one, so the answer is the maximum element in nums.
      • If n == 1 and k is odd, you will end up with an empty stack, so return -1.

Implementation Tips:

  • Use slicing or loops to find the maximum among the first k-1 elements.
  • Always check for out-of-bounds when k is close to the length of nums.

Example Walkthrough

Let's consider nums = [2, 4, 1, 5, 3] and k = 3:

  1. You can remove up to k-1 = 2 elements and put back any one of them as the top, or just remove 3 elements and have nums[3] = 5 as the new top.
  2. The first k-1 = 2 elements are 2 and 4. The maximum is 4.
  3. The third element (nums[3]) is 5.
  4. So, the answer is max(4, 5) = 5.

If nums = [1] and k = 1:

  • Removing the only element leaves the stack empty after 1 move, so return -1.

Time and Space Complexity

Brute-force Approach:

  • Would involve simulating all possible sequences of removes and puts, leading to exponential time complexity: O(2^k).
Optimized Approach:
  • We only need to find the maximum among the first k-1 elements, and possibly compare with nums[k] (if k < n), so the time complexity is O(k).
  • Space complexity is O(1), since we only store a few variables for tracking the maximum.

Summary

The key to solving this problem efficiently is recognizing that you can only ever put back elements you've removed, and you can't do more than one operation per move. By focusing on the first k-1 elements and considering the k-th element, we avoid brute-force and quickly compute the answer. This approach is both elegant and efficient, leveraging careful analysis of the stack operations and move constraints.

Code Implementation

class Solution:
    def maximizeTopmostElement(self, nums: List[int], k: int) -> int:
        n = len(nums)
        if k == 0:
            return nums[0] if n > 0 else -1
        if n == 1:
            # If k is odd, stack is empty, else the only element remains
            return -1 if k % 2 == 1 else nums[0]
        if k == 1:
            return nums[1] if n > 1 else -1
        if k >= n:
            return max(nums)
        # Consider the max among the first k-1 elements and nums[k]
        max_in_prefix = max(nums[:k-1])
        # Optionally, nums[k] can be the new top if we just keep removing
        if k < n:
            return max(max_in_prefix, nums[k])
        else:
            return max_in_prefix
      
class Solution {
public:
    int maximizeTopmostElement(vector<int>& nums, int k) {
        int n = nums.size();
        if (k == 0) return n > 0 ? nums[0] : -1;
        if (n == 1) return (k % 2 == 1) ? -1 : nums[0];
        if (k == 1) return n > 1 ? nums[1] : -1;
        if (k >= n) {
            int mx = nums[0];
            for (int i = 1; i < n; ++i) mx = max(mx, nums[i]);
            return mx;
        }
        int mx = nums[0];
        for (int i = 1; i < k - 1; ++i) mx = max(mx, nums[i]);
        return max(mx, nums[k]);
    }
};
      
class Solution {
    public int maximizeTopmostElement(int[] nums, int k) {
        int n = nums.length;
        if (k == 0) return n > 0 ? nums[0] : -1;
        if (n == 1) return (k % 2 == 1) ? -1 : nums[0];
        if (k == 1) return n > 1 ? nums[1] : -1;
        if (k >= n) {
            int mx = nums[0];
            for (int i = 1; i < n; ++i) mx = Math.max(mx, nums[i]);
            return mx;
        }
        int mx = nums[0];
        for (int i = 1; i < k - 1; ++i) mx = Math.max(mx, nums[i]);
        return Math.max(mx, nums[k]);
    }
}
      
var maximizeTopmostElement = function(nums, k) {
    let n = nums.length;
    if (k === 0) return n > 0 ? nums[0] : -1;
    if (n === 1) return (k % 2 === 1) ? -1 : nums[0];
    if (k === 1) return n > 1 ? nums[1] : -1;
    if (k >= n) {
        return Math.max(...nums);
    }
    let mx = nums[0];
    for (let i = 1; i < k - 1; ++i) {
        mx = Math.max(mx, nums[i]);
    }
    return Math.max(mx, nums[k]);
};