# 503. Next Greater Element II
LeetCode Problem Link (opens new window)
Given a circular array (the next element of the last element is the first element of the array), output the next greater number for every element. The next greater number of a number x is the first greater number to its traversing-order-next in the array, which means you should search circularly to find its next greater number. If it doesn't exist, output -1 for this number.
Example 1:
- Input:
[1,2,1] - Output:
[2,-1,2] - Explanation: The next greater number of the first 1 is 2; for number 2 no next greater number exists; the next greater number of the second 1 needs to be searched circularly, which is also 2.
Note:
- 1 <=
nums.length<= 10^4 - -10^9 <=
nums[i]<= 10^9
# Solution
Before solving this problem, it's recommended to solve 0739.Daily Temperatures (opens new window) and 0496.Next Greater Element I (opens new window).
This problem is very similar to 0739.Daily Temperatures (opens new window).
However, this problem involves a circular array.
About the explanation of monotonic stack, I have already covered it in detail in the solution for 0739.Daily Temperatures (opens new window).
Here, I will focus on how to handle circular arrays.
Some might think that directly concatenating two arrays and then using a monotonic stack to find the next greater number would solve the issue!
Indeed, it is possible!
You can concatenate the nums array with itself, use a monotonic stack to compute the next greater number for each element, and finally resize the result array to the original array's size.
Here is the code:
// Version 1
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
// Concatenate a new nums
vector<int> nums1(nums.begin(), nums.end());
nums.insert(nums.end(), nums1.begin(), nums1.end());
// Initialize result with the new nums' size
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
// Start monotonic stack
stack<int> st;
st.push(0);
for (int i = 1; i < nums.size(); i++) {
if (nums[i] < nums[st.top()]) st.push(i);
else if (nums[i] == nums[st.top()]) st.push(i);
else {
while (!st.empty() && nums[i] > nums[st.top()]) {
result[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
}
// Finally, resize result to the original array size
result.resize(nums.size() / 2);
return result;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
This approach is indeed straightforward, but there are a lot of unnecessary operations, such as modifying the nums array, and you need to resize the result array at the end.
Resizing is not time-consuming as it's an O(1) operation, but expanding the nums array equivalent to an O(n) operation.
Actually, you don't have to expand nums but simulate traversing two rounds of nums during the iteration.
Here is the code:
// Version 2
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
stack<int> st;
st.push(0);
for (int i = 1; i < nums.size() * 2; i++) {
// Simulating traversing two rounds of nums, notice that all operations use i % nums.size()
if (nums[i % nums.size()] < nums[st.top()]) st.push(i % nums.size());
else if (nums[i % nums.size()] == nums[st.top()]) st.push(i % nums.size());
else {
while (!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
result[st.top()] = nums[i % nums.size()];
st.pop();
}
st.push(i % nums.size());
}
}
return result;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Version two not only simplifies the code but also avoids unnecessary operations compared to version one!
Finally, here’s a concise version of the monotonic stack, consolidating the three conditions:
// Version 2
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
stack<int> st;
for (int i = 0; i < nums.size() * 2; i++) {
// Simulating traversing two rounds of nums, notice that all operations use i % nums.size()
while (!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
result[st.top()] = nums[i % nums.size()];
st.pop();
}
st.push(i % nums.size());
}
return result;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Other Language Versions
# Java:
class Solution {
public int[] nextGreaterElements(int[] nums) {
// Edge case check
if(nums == null || nums.length <= 1) {
return new int[]{-1};
}
int size = nums.length;
int[] result = new int[size]; // To store results
Arrays.fill(result,-1); // Default initialize all to -1
Stack<Integer> st= new Stack<>(); // Stack to store indices of nums
for(int i = 0; i < 2*size; i++) {
while(!st.empty() && nums[i % size] > nums[st.peek()]) {
result[st.peek()] = nums[i % size]; // Update result
st.pop(); // Pop top
}
st.push(i % size);
}
return result;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Python:
Version One:
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
dp = [-1] * len(nums)
stack = []
for i in range(len(nums)*2):
while(len(stack) != 0 and nums[i%len(nums)] > nums[stack[-1]]):
dp[stack[-1]] = nums[i%len(nums)]
stack.pop()
stack.append(i%len(nums))
return dp
2
3
4
5
6
7
8
9
10
Version Two: Optimization for Version One
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
res = [-1] * len(nums)
stack = []
# First traversal of nums
for i, num in enumerate(nums):
while stack and num > nums[stack[-1]]:
res[stack[-1]] = num
stack.pop()
stack.append(i)
# At this point, the stack still has remnants, with some numbers needing updates for "no next greater number"
# Second traversal of nums
for num in nums:
# If the stack is empty, all numbers have a next greater element, so return the result
if not stack:
return res
while stack and num > nums[stack[-1]]:
res[stack[-1]] = num
stack.pop()
# Do not add numbers that already have a next greater element to the stack, this prevents redundant assignments; only attempt to find the next greater element for leftovers from the first traversal.
# Finally, some larger numbers may not have a next greater element, return the result
return res
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Go:
// Version one
func nextGreaterElements(nums []int) []int {
// Concatenate a new nums
numsNew := make([]int, len(nums) * 2)
copy(numsNew, nums)
copy(numsNew[len(nums):], nums)
// Initialize result with a new nums size
result := make([]int, len(numsNew))
for i := range result {
result[i] = -1
}
// Start monotonic stack
st := []int{0}
for i := 1; i < len(numsNew); i++ {
if numsNew[i] < numsNew[st[len(st)-1]] {
st = append(st, i)
} else if numsNew[i] == numsNew[st[len(st)-1]] {
st = append(st, i)
} else {
for len(st) > 0 && numsNew[i] > numsNew[st[len(st)-1]] {
result[st[len(st)-1]] = numsNew[i]
st = st[:len(st)-1]
}
st = append(st, i)
}
}
result = result[:len(result)/2]
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Version two
func nextGreaterElements(nums []int) []int {
length := len(nums)
result := make([]int,length)
for i:=0;i<len(result);i++{
result[i] = -1
}
// Monotonically decreasing, store indices
stack := make([]int, 0)
for i:=0; i < length*2; i++{
for len(stack) > 0 && nums[i%length] > nums[stack[len(stack)-1]]{
index := stack[len(stack)-1]
stack = stack[:len(stack)-1] // pop
result[index] = nums[i%length]
}
stack = append(stack, i%length)
}
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# JavaScript:
/**
* @param {number[]} nums
* @return {number[]}
*/
var nextGreaterElements = function (nums) {
const len = nums.length;
let stack = [];
let res = Array(len).fill(-1);
for (let i = 0; i < len * 2; i++) {
while (
stack.length &&
nums[i % len] > nums[stack[stack.length - 1]]
) {
const index = stack.pop();
res[index] = nums[i % len];
}
stack.push(i % len);
}
return res;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# TypeScript:
function nextGreaterElements(nums: number[]): number[] {
const length: number = nums.length;
const stack: number[] = [];
stack.push(0);
const resArr: number[] = new Array(length).fill(-1);
for (let i = 1; i < length * 2; i++) {
const index = i % length;
let top = stack[stack.length - 1];
while (stack.length > 0 && nums[top] < nums[index]) {
resArr[top] = nums[index];
stack.pop();
top = stack[stack.length - 1];
}
if (i < length) {
stack.push(i);
}
}
return resArr;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Rust:
impl Solution {
pub fn next_greater_elements(nums: Vec<i32>) -> Vec<i32> {
let mut ans = vec![-1; nums.len() * 2];
let mut stack = vec![];
let double = nums.repeat(2);
for (idx, &i) in double.iter().enumerate() {
while !stack.is_empty() && double[*stack.last().unwrap()] < i {
let pos = stack.pop().unwrap();
ans[pos] = i;
}
stack.push(idx);
}
ans.into_iter().take(nums.len()).collect()
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Version Two:
impl Solution {
pub fn next_greater_elements(nums: Vec<i32>) -> Vec<i32> {
let (mut stack, mut res) = (vec![], vec![-1; nums.len()]);
for i in 0..nums.len() * 2 {
while let Some(&top) = stack.last() {
if nums[i % nums.len()] <= nums[top] {
break;
}
let saved_index = stack.pop().unwrap();
res[saved_index] = nums[i % nums.len()];
}
stack.push(i % nums.len());
}
res
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18