1299. Replace Elements with Greatest Element on Right Side
Problem Description
You are given an array arr
. Your task is to transform this array by replacing each element with the greatest element that appears to its right in the array. The last element should be replaced with -1
since there are no elements to its right.
For example, if you have an array [17, 18, 5, 4, 6, 1]
:
- Element at index 0 (17) is replaced by the maximum of all elements to its right:
max(18, 5, 4, 6, 1) = 18
- Element at index 1 (18) is replaced by the maximum of all elements to its right:
max(5, 4, 6, 1) = 6
- Element at index 2 (5) is replaced by the maximum of all elements to its right:
max(4, 6, 1) = 6
- Element at index 3 (4) is replaced by the maximum of all elements to its right:
max(6, 1) = 6
- Element at index 4 (6) is replaced by the maximum of all elements to its right:
max(1) = 1
- Element at index 5 (1) is the last element, so it's replaced by
-1
The resulting array would be [18, 6, 6, 6, 1, -1]
.
The solution uses a reverse traversal approach. By iterating from right to left, we can keep track of the maximum value seen so far. At each position, we store the current maximum in that position and update our maximum tracker with the original value at that position. This way, each element gets replaced with the greatest element to its right efficiently in a single pass through the array.
Intuition
The key insight is that if we traverse the array from left to right, we would need to repeatedly scan the remaining elements to find the maximum for each position, which would be inefficient. However, if we traverse from right to left, we can maintain the maximum value seen so far and use it directly.
Think about it this way: when we're at the rightmost element, we know it should be replaced with -1
. As we move left, each element needs the maximum of all elements to its right. But we've just visited those elements! So we can keep track of the running maximum as we go.
The clever part is realizing that at each position during our reverse traversal:
- We already know what the maximum value to the right is (stored in our
mx
variable) - Before overwriting the current element, we need to save it to potentially update our maximum
- After replacing the current element with
mx
, we updatemx
to bemax(mx, original_value)
for the next iteration
This way, we build our answer in a single pass. Starting from the right with mx = -1
ensures the last element gets -1
as required. As we move left, mx
always contains the maximum of all elements we've seen so far (which are all the elements to the right of our current position).
The beauty of this approach is that we're essentially "carrying" the information we need (the maximum value) as we traverse, rather than recalculating it each time. This transforms what could be an O(n²) problem into an O(n) solution.
Solution Approach
The implementation uses a single-pass reverse traversal with a tracking variable to efficiently solve the problem.
Algorithm Steps:
-
Initialize the maximum tracker: Start with
mx = -1
. This serves as the initial value for the rightmost element (which has no elements to its right). -
Reverse traversal: Use
reversed(range(len(arr)))
to iterate through array indices from right to left. This allows us to process each element while having already seen all elements to its right. -
For each position
i
:- Store the original value: Save
arr[i]
in a temporary variablex
before overwriting it - Replace with maximum: Set
arr[i] = mx
(the maximum of all elements to the right) - Update the maximum: Calculate
mx = max(mx, x)
to include the current element for future iterations
- Store the original value: Save
-
Return the modified array: The array is modified in-place and returned.
Example walkthrough with [17, 18, 5, 4, 6, 1]
:
- Start:
mx = -1
- Index 5 (value 1):
x = 1
,arr[5] = -1
,mx = max(-1, 1) = 1
- Index 4 (value 6):
x = 6
,arr[4] = 1
,mx = max(1, 6) = 6
- Index 3 (value 4):
x = 4
,arr[3] = 6
,mx = max(6, 4) = 6
- Index 2 (value 5):
x = 5
,arr[2] = 6
,mx = max(6, 5) = 6
- Index 1 (value 18):
x = 18
,arr[1] = 6
,mx = max(6, 18) = 18
- Index 0 (value 17):
x = 17
,arr[0] = 18
,mx = max(18, 17) = 18
- Result:
[18, 6, 6, 6, 1, -1]
The time complexity is O(n) as we visit each element exactly once, and the space complexity is O(1) since we only use a constant amount of extra space for the tracking variable.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a small example: arr = [5, 2, 3, 1]
Initial Setup:
- Start with
mx = -1
(this will be the value for the last element) - We'll traverse from right to left
Step-by-step execution:
Index 3 (value = 1):
- Save original:
x = 1
- Replace with max to the right:
arr[3] = mx = -1
- Update max for next iteration:
mx = max(-1, 1) = 1
- Array now:
[5, 2, 3, -1]
Index 2 (value = 3):
- Save original:
x = 3
- Replace with max to the right:
arr[2] = mx = 1
- Update max for next iteration:
mx = max(1, 3) = 3
- Array now:
[5, 2, 1, -1]
Index 1 (value = 2):
- Save original:
x = 2
- Replace with max to the right:
arr[1] = mx = 3
- Update max for next iteration:
mx = max(3, 2) = 3
- Array now:
[5, 3, 1, -1]
Index 0 (value = 5):
- Save original:
x = 5
- Replace with max to the right:
arr[0] = mx = 3
- Update max for next iteration:
mx = max(3, 5) = 5
- Array now:
[3, 3, 1, -1]
Final Result: [3, 3, 1, -1]
Each element has been replaced with the greatest element to its right:
- 5 → 3 (max of 2, 3, 1)
- 2 → 3 (max of 3, 1)
- 3 → 1 (max of 1)
- 1 → -1 (no elements to the right)
Solution Implementation
1class Solution:
2 def replaceElements(self, arr: List[int]) -> List[int]:
3 """
4 Replace each element with the greatest element to its right.
5 The last element is replaced with -1.
6
7 Args:
8 arr: Input array of integers
9
10 Returns:
11 Modified array where each element is replaced by the max element to its right
12 """
13 # Initialize the maximum value seen so far (starts with -1 for the last element)
14 max_so_far = -1
15
16 # Traverse the array from right to left
17 for i in reversed(range(len(arr))):
18 # Store the current element before replacing it
19 current_element = arr[i]
20
21 # Replace current element with the maximum element seen to its right
22 arr[i] = max_so_far
23
24 # Update the maximum to include the current element
25 max_so_far = max(max_so_far, current_element)
26
27 return arr
28
1class Solution {
2 public int[] replaceElements(int[] arr) {
3 // Initialize maximum value to -1 (as per problem requirement for last element)
4 int maxValue = -1;
5
6 // Traverse the array from right to left
7 for (int i = arr.length - 1; i >= 0; i--) {
8 // Store current element temporarily before overwriting
9 int currentElement = arr[i];
10
11 // Replace current element with the maximum value seen so far (to its right)
12 arr[i] = maxValue;
13
14 // Update maximum value to include the current element for next iteration
15 maxValue = Math.max(maxValue, currentElement);
16 }
17
18 return arr;
19 }
20}
21
1class Solution {
2public:
3 vector<int> replaceElements(vector<int>& arr) {
4 // Start from the rightmost element and move left
5 // Initialize max_right to -1 (for the last element)
6 int max_right = -1;
7
8 // Iterate from right to left through the array
9 for (int i = arr.size() - 1; i >= 0; --i) {
10 // Store the current element before replacing it
11 int current_element = arr[i];
12
13 // Replace current element with the maximum element to its right
14 arr[i] = max_right;
15
16 // Update max_right to include the current element
17 // This will be used for the next iteration (element to the left)
18 max_right = max(max_right, current_element);
19 }
20
21 return arr;
22 }
23};
24
1/**
2 * Replaces each element in the array with the greatest element among
3 * the elements to its right, and replaces the last element with -1.
4 * @param arr - The input array of numbers to process
5 * @returns The modified array with elements replaced
6 */
7function replaceElements(arr: number[]): number[] {
8 // Start from the last element, initialize max value as -1
9 let maxValue: number = -1;
10
11 // Iterate through the array from right to left
12 for (let i: number = arr.length - 1; i >= 0; i--) {
13 // Store current element before replacing it
14 const currentElement: number = arr[i];
15
16 // Replace current element with the maximum value seen so far (from the right)
17 arr[i] = maxValue;
18
19 // Update the maximum value for the next iteration
20 maxValue = Math.max(maxValue, currentElement);
21 }
22
23 return arr;
24}
25
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array. The algorithm iterates through the array exactly once in reverse order using reversed(range(len(arr)))
, performing constant-time operations (assignment, comparison with max()
) at each step.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space - two variables mx
and x
- regardless of the input size. The modifications are done in-place on the original array, and the reversed()
function returns an iterator that doesn't create a new list, maintaining constant space usage.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Store the Original Value Before Overwriting
One of the most common mistakes is directly updating arr[i]
without first storing its original value. This leads to losing the element's value before it can be used to update the maximum tracker.
Incorrect Implementation:
def replaceElements(self, arr: List[int]) -> List[int]:
max_so_far = -1
for i in reversed(range(len(arr))):
arr[i] = max_so_far # Original value is lost!
max_so_far = max(max_so_far, arr[i]) # Now using the replaced value (wrong!)
return arr
Why it fails: After setting arr[i] = max_so_far
, the original value at position i
is lost. When updating max_so_far
, we're using the already-replaced value instead of the original element, which breaks the algorithm.
Correct Solution:
def replaceElements(self, arr: List[int]) -> List[int]:
max_so_far = -1
for i in reversed(range(len(arr))):
current_element = arr[i] # Store original value first
arr[i] = max_so_far
max_so_far = max(max_so_far, current_element) # Use the stored original value
return arr
2. Traversing in the Wrong Direction (Left to Right)
Another pitfall is attempting to solve this problem by traversing from left to right, which seems intuitive but makes the solution unnecessarily complex.
Why left-to-right doesn't work efficiently: When at position i
, you need to know the maximum of all elements from i+1
to the end. With left-to-right traversal, you'd need to either:
- Scan ahead for each element (O(n²) time complexity)
- Use additional data structures to precompute maximums
Right-to-left is optimal because: When processing element at index i
, you've already processed all elements to its right and know their maximum, making it a single O(n) pass solution.
3. Incorrect Initial Value for Maximum Tracker
Setting the wrong initial value for max_so_far
can cause incorrect results, especially for the last element.
Incorrect:
max_so_far = 0 # Wrong initial value
Why it fails: If all elements in the array are negative, using 0 as the initial value would incorrectly report 0 as the maximum to the right of some elements.
Correct: Always initialize with -1
as specified in the problem, since the last element should always be replaced with -1
.
Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!