2202. Maximize the Topmost Element After K Moves
Problem Description
In this problem, we have an array nums
that represents the contents of a pile with an index starting at 0. The element at index 0 (nums[0]
) is at the top of the pile. There are two types of moves we can perform on this pile:
- Remove the topmost element of the pile, if the pile is not empty.
- Add any one of the previously removed elements back onto the top of the pile, assuming there's at least one removed element available.
We are also given an integer k
, which represents the total number of moves that have to be made.
Objective: Our task is to find out the maximum possible value of the element at the top of the pile after making exactly k
moves. If it's not possible to have any elements left in the pile after k
moves, we should return -1
.
This problem requires us to manipulate the topmost element of a pile with some constraints and to plan the moves to maximize the value of the topmost element taking into consideration the number of available moves.
Intuition
To find the solution, we need to consider the number of elements in the pile and the number of available moves, k
. We can break this down into different scenarios:
-
If
k
is 0, we do not need to make any moves, and we simply return the current topmost element,nums[0]
. -
If there is only one element in the pile (
len(nums) == 1
) andk
is odd, we will inevitably end up with an empty pile after these moves since each odd move removes the last element and each even move can't put it back (as there's no other to add). Hence, in this case, the answer is-1
. -
If
k
is less than the number of elements in the pile (k < len(nums)
), we need to get the maximum between two potential topmost elements:- The largest element from the range
nums[0]
tonums[k-1]
, acknowledging that we can makek-1
removals and then put the maximum number back on the pile. - The element at index
k
(nums[k]
), since it can be the top of the pile if we removek
elements (one of them being thisnums[k]
) and then putnums[k]
back.
- The largest element from the range
-
If
k
is greater or equal to the number of elements (k >= len(nums)
), we only look at the maximum element within the bounds ofnums
in the firstk-1
moves. Thek-th
move could be adding an element back if there are still remaining moves.
By considering these scenarios, we can design the solution which ensures that we return the maximum topmost value after k
moves, or -1
if it's not possible to perform k
moves and still have elements left in the pile.
Learn more about Greedy patterns.
Solution Approach
The provided solution is straightforward and makes use of conditional checks and the max
function to compare elements within the nums
array based on different scenarios discussed in the intuition section.
Here's a step-by-step explanation of the implementation:
-
Check for No Moves (
k == 0
): If the number of movesk
is0
, we simply return the topmost element as no moves are made.if k == 0: return nums[0]
-
Check for Single Element Piles (
n == 1
): If the pile has only one element, we need to check ifk
is an odd number. Ifk
is odd, we will end up with no element at the top, so return-1
. Ifk
is even, we can keep removing and adding the same element, effectively making no changes, and we return the topmost element.n = len(nums) if n == 1: if k % 2: return -1 return nums[0]
-
Find Maximum with Constraints: We then find the maximum value from the array up to the
k-1
index. This is because afterk-1
removals, we could replace the topmost element with one of the removed elements. We use themax
function over the slicenums[: k - 1]
, and usedefault=-1
to handle the edge case where the slice could be empty.ans = max(nums[: k - 1], default=-1)
-
Consider Element at Index
k
: Ifk
is less than the length of the array (k < n
), it means the element at the indexk
could be a candidate for the maximum topmost element afterk
moves. We should choose the larger between the currentans
andnums[k]
.if k < n: ans = max(ans, nums[k])
-
Return the Result: Finally, we return
ans
as the maximum possible value for the top of the pile after exactlyk
moves.
In terms of data structures, the solution simply uses the list (array) given, without the need for additional data structures. The key algorithmic pattern here is the greedy approach, selecting the largest value at each step with consideration to the constraints given by k
and the number of elements n
. The implementation uses basic array operations and conditions to achieve the desired outcome.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take a small example to illustrate the solution approach. Suppose we are given the following array of integers representing our pile:
nums = [4, 1, 5, 6]
and we have k = 3
moves to make.
Following the solution steps:
-
Since
k
is not0
, we do not returnnums[0]
right away. We proceed with the next steps. -
There is more than one element in the pile (
len(nums) = 4
), so we do not need to consider the scenario wherek
is odd, and we only have one element. -
We find the maximum value from the array up to the
k-1
index, which is2
in this case, so we considernums
up to and including index1
:nums[:k-1] = [4, 1]
. We find the maximum value in this range:ans = max(nums[:2]) # The maximum value from [4, 1] which is 4.
So,
ans
is now4
. -
Since
k
is less than the length of the array (k < n
), we consider the element at indexk
, which isnums[3] = 6
. We then compare it with our currentans
and select the larger value:ans = max(ans, nums[3]) # We compare 4 and 6.
So,
ans
is updated to6
. -
After evaluating the given conditions, we have determined that the maximum value we can have at the top of the pile after exactly
3
moves is6
.
We can now visualize the moves:
- First move: we remove the topmost element
4
from the pile, now the pile is[1, 5, 6]
. - Second move: we remove the topmost element
1
from the pile, now the pile is[5, 6]
. - Third move: we add an element back to the pile, and we have the option to add either
1
or4
. We choose4
as it is the larger value. However, we also realize that the remaining element6
can be placed on top as it is the largest of all the elements we have, even larger than4
. Thus, we opt to place6
on top instead, leading to our answer.
Therefore, the maximum possible value for the top of the pile after exactly 3
moves is 6
.
Solution Implementation
1class Solution:
2 def maximumTop(self, nums: List[int], k: int) -> int:
3 # If we cannot perform any operations, return the top element immediately.
4 if k == 0:
5 return nums[0]
6
7 # Get the number of elements in the stack.
8 num_elements = len(nums)
9
10 # If there's only one element in the stack and k is odd,
11 # we will never be able to put any element at the top after removal.
12 if num_elements == 1:
13 # If k is odd, it means we end up with an empty stack and nothing to replace the top
14 return -1 if k % 2 == 1 else nums[0]
15
16 # Find the maximum value in the stack within the range of available operations.
17 # We exclude the k-th element because if we are able to reach it,
18 # it means we have removed the original top and haven't replaced it yet.
19 max_value = max(nums[:k - 1], default=-1)
20
21 # If k is less than the number of elements, we can consider
22 # the k-th element as a candidate for the maximum top element
23 # after performing the operations.
24 if k < num_elements:
25 # 'nums[k]' is the element just after 'k - 1' operations, it might be the largest.
26 max_value = max(max_value, nums[k])
27
28 return max_value
29
1class Solution {
2 public int maximumTop(int[] nums, int k) {
3 // If no moves are allowed (k is zero), we return the top number on the stack
4 if (k == 0) {
5 return nums[0];
6 }
7
8 // Get the number of elements in the stack
9 int stackSize = nums.length;
10
11 // Special case when there's only one number in the stack
12 if (stackSize == 1) {
13 // If k is odd, we end up with an empty stack
14 if (k % 2 == 1) {
15 return -1;
16 }
17 // If k is even, we can restore the same number back to the stack
18 return nums[0];
19 }
20
21 // Initialize the answer to an impossible value, signaling not found yet
22 int maximumValue = -1;
23
24 // Look for the maximum number that can be the top of the stack
25 // either by removing the top k-1 numbers or by not changing the stack.
26 for (int i = 0; i < Math.min(k - 1, stackSize); ++i) {
27 maximumValue = Math.max(maximumValue, nums[i]);
28 }
29
30 // If k is less than the stack size, we must also consider the k-th number in the stack,
31 // since it can be on top after k-1 operations.
32 if (k < stackSize) {
33 maximumValue = Math.max(maximumValue, nums[k]);
34 }
35
36 // Return the maximum number that can be on top of the stack
37 return maximumValue;
38 }
39}
40
1class Solution {
2public:
3 int maximumTop(vector<int>& nums, int k) {
4 // If no operation is to be performed, simply return the top element.
5 if (k == 0) return nums[0];
6
7 // The variable `n` holds the size of the vector `nums`.
8 int n = nums.size();
9
10 // If we only have one number and an odd number of moves, we can never have a top.
11 if (n == 1) {
12 if (k % 2) return -1;
13 return nums[0];
14 }
15
16 // Initialize the maximum number we can get to negative, since we can't get a negative index.
17 int maxNumber = -1;
18
19 // Check until lesser of k-1 or n for the possible maximum number on top.
20 for (int i = 0; i < min(k - 1, n); ++i) {
21 maxNumber = max(maxNumber, nums[i]);
22 }
23
24 // If we have more than k elements, check if the kth element can be the top.
25 if (k < n) {
26 maxNumber = max(maxNumber, nums[k]);
27 }
28
29 // Return the maximum number that could be on top after k moves.
30 return maxNumber;
31 }
32};
33
1function maximumTop(nums: number[], k: number): number {
2 // If no operation is to be performed, simply return the topmost element.
3 if (k === 0) return nums[0];
4
5 // Variable `n` holds the size of the array `nums`.
6 let n: number = nums.length;
7
8 // If there is only one number and an odd number of moves,
9 // we can never have a top, so return -1.
10 if (n === 1) {
11 if (k % 2) return -1;
12 return nums[0];
13 }
14
15 // Initialize `maxNumber` as negative, to represent that we have not yet found a feasible number.
16 let maxNumber: number = -1;
17
18 // Search for the maximum number within the bounds of `k - 1` or `n`
19 // which could be the top element after performing `k - 1` moves.
20 for (let i: number = 0; i < Math.min(k - 1, n); ++i) {
21 maxNumber = Math.max(maxNumber, nums[i]);
22 }
23
24 // If there are more than `k` elements, it is possible to place
25 // the `k`-th element on top after performing `k` operations.
26 if (k < n) {
27 maxNumber = Math.max(maxNumber, nums[k]);
28 }
29
30 // Return the maximum number that could be on top after performing `k` moves.
31 return maxNumber;
32}
33
Time and Space Complexity
The time complexity of the given code is O(k)
, where k
is the number of operations to be performed on the nums
array. This is because the code potentially examines elements up to the k-1
position in the nums
array to find the maximum value, and the number of elements looked at is limited by k
. When k < n
, it also compares the value at the k
-th position once, which does not affect the overall time complexity.
The space complexity of the code is O(1)
since the code only uses a constant amount of additional space. The variables n
and ans
are used to store the length of the nums
array and the interim maximum values, respectively, and they do not depend on the size of the input array.
Learn more about how to find time and space complexity quickly using problem constraints.
How does merge sort divide the problem into subproblems?
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
LeetCode 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 we
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 algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!