Given a circular integer array nums
(i.e., the next element of nums[nums.length - 1]
is nums[0]
), return the next greater number for every element in nums
.
The next greater number of a number x
is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, return -1
for this number.
Example 1:
Input: nums = [1,2,1] Output: [2,-1,2] Explanation: The first 1's next greater number is 2; The number 2 can't find next greater number. The second 1's next greater number needs to search circularly, which is also 2.
Example 2:
Input: nums = [1,2,3,4,3] Output: [2,3,4,-1,4]
Constraints:
1 <= nums.length <= 104
-109 <= nums[i] <= 109
This problem asks to find the next greater element for each element in a circular integer array. A circular array means the element after the last element is the first element. If no greater element exists, we return -1.
The most efficient approach uses a monotonic stack. A monotonic stack is a stack that maintains a specific order (increasing or decreasing). In this case, we'll use a decreasing monotonic stack.
Algorithm:
Initialization: Create an array ans
of the same size as nums
, initialized with -1. This array will store the next greater element for each index. Also, initialize an empty stack stk
.
Iteration: Iterate through the nums
array twice (to handle the circularity). We iterate backward from 2*n - 1
to 0, where n
is the length of nums
. This backward iteration simplifies finding the "next" greater element. The modulo operator (%
) ensures we wrap around the array correctly.
Stack Operations: For each element nums[j]
(where j = i % n
):
stk[-1]
) is less than or equal to nums[j]
, pop elements from the stack. This ensures that the stack always contains decreasing elements.nums[j]
. Assign this value to ans[j]
.nums[j]
onto the stack.Return: Return the ans
array.
Time Complexity: O(n). Each element is pushed and popped at most once onto the stack.
Space Complexity: O(n) in the worst case, as the stack could potentially hold all the elements of nums
.
Code Examples (Python and Java):
Python:
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
n = len(nums)
ans = [-1] * n
stk = []
for i in range(n * 2 - 1, -1, -1):
j = i % n
while stk and stk[-1] <= nums[j]:
stk.pop()
if stk:
ans[j] = stk[-1]
stk.append(nums[j])
return ans
Java:
import java.util.*;
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
Arrays.fill(ans, -1);
Deque<Integer> stk = new ArrayDeque<>();
for (int i = 2 * n - 1; i >= 0; --i) {
int j = i % n;
while (!stk.isEmpty() && stk.peek() <= nums[j]) {
stk.pop();
}
if (!stk.isEmpty()) {
ans[j] = stk.peek();
}
stk.push(nums[j]);
}
return ans;
}
}
The other languages (C++, Go, TypeScript, JavaScript) follow a very similar structure, using their respective stack implementations. The core logic remains the same: a decreasing monotonic stack to efficiently find the next greater element in a circular array.