|
| 1 | +# 503. Next Greater Element II |
| 2 | + |
| 3 | +**Difficulty:** Medium |
| 4 | +**Category:** Arrays, Stack, Monotonic Stack |
| 5 | +**Leetcode Link:** [Problem Link](https://leetcode.com/problems/next-greater-element-ii) |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## 📝 Introduction |
| 10 | + |
| 11 | +Given a circular array, the task is to find the next greater element for each element in the array. The "next greater element" for a number x is the first greater number traversing the array in the forward direction. If it doesn’t exist, assign -1. Since the array is circular, we simulate traversing the array twice. |
| 12 | + |
| 13 | +Constraints typically include:<br> |
| 14 | +- 1 ≤ nums.length ≤ 10⁴ |
| 15 | +- -10⁹ ≤ nums[i] ≤ 10⁹ |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## 💡 Approach & Key Insights |
| 20 | + |
| 21 | +The brute force solution involves checking for the next greater element by looping through the array for each element. This leads to O(n²) time complexity. |
| 22 | + |
| 23 | +The optimized approach uses a monotonic decreasing stack and processes the array twice to simulate circularity. While traversing in reverse, we pop elements smaller than or equal to the current one from the stack. If the stack is not empty, the top is the next greater element. |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 🛠️ Breakdown of Approaches |
| 28 | + |
| 29 | +### 1️⃣ Brute Force / Naive Approach |
| 30 | + |
| 31 | +- **Explanation:** |
| 32 | + For each element, we look forward in the array (circularly) to find the next greater number. This requires a nested loop. |
| 33 | +- **Time Complexity:** O(n²) – We iterate through the array for each element. |
| 34 | +- **Space Complexity:** O(1) – No extra space except for the output. |
| 35 | +- **Example/Dry Run:** |
| 36 | + |
| 37 | +```plaintext |
| 38 | +Input: [1, 2, 1] |
| 39 | +i = 0 → 2 is next greater → ans[0] = 2 |
| 40 | +i = 1 → no element greater → ans[1] = -1 |
| 41 | +i = 2 → 2 is next greater (wraps around) → ans[2] = 2 |
| 42 | +Output: [2, -1, 2] |
| 43 | +``` |
| 44 | + |
| 45 | +### 2️⃣ Optimized Approach |
| 46 | + |
| 47 | +- **Explanation:** |
| 48 | + We use a stack to maintain indices in a decreasing order of values. We traverse the array twice in reverse order to simulate the circular array. At each index, we pop all smaller or equal values. If the stack is not empty, the top of the stack is the next greater element. |
| 49 | +- **Time Complexity:** O(n) – Each element is pushed and popped at most once. |
| 50 | +- **Space Complexity:** O(n) – For the stack and output array. |
| 51 | +- **Example/Dry Run:** |
| 52 | + |
| 53 | +```plaintext |
| 54 | +Input: [1, 2, 1] |
| 55 | +Initialize ans = [-1, -1, -1] |
| 56 | +Pass 1 (i = 5 to 0): (simulate 2*n = 6 steps) |
| 57 | +
|
| 58 | +i=5 → idx=2 → stack=[], ans[2]=-1 → push 1 |
| 59 | +i=4 → idx=1 → stack=[1], 2>1 → pop → stack=[], ans[1]=-1 → push 2 |
| 60 | +i=3 → idx=0 → stack=[2], 2>1 → ans[0]=2 → push 1 |
| 61 | +i=2 → idx=2 → stack=[2,1], top=1==1 → pop → stack=[2], top=2>1 → ans[2]=2 → push 1 |
| 62 | +i=1 → idx=1 → top=1<2 → ans[1]=-1 (already assigned) → push 2 |
| 63 | +i=0 → idx=0 → ans[0]=2 (already assigned) |
| 64 | +
|
| 65 | +Final Output: [2, -1, 2] |
| 66 | +``` |
| 67 | + |
| 68 | +### 3️⃣ Best / Final Optimized Approach |
| 69 | + |
| 70 | +- **Explanation:** |
| 71 | + Same as optimized above using a monotonic decreasing stack. The idea of traversing 2n times in reverse is optimal and handles circularity efficiently. |
| 72 | +- **Time Complexity:** O(n) – Each index is processed at most twice. |
| 73 | +- **Space Complexity:** O(n) – Stack and output array. |
| 74 | + |
| 75 | +--- |
| 76 | + |
| 77 | +## 📊 Complexity Analysis |
| 78 | + |
| 79 | +| Approach | Time Complexity | Space Complexity | |
| 80 | +| ------------- | --------------- | ---------------- | |
| 81 | +| Brute Force | O(n²) | O(1) | |
| 82 | +| Optimized | O(n) | O(n) | |
| 83 | +| Best Approach | O(n) | O(n) | |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## 📉 Optimization Ideas |
| 88 | + |
| 89 | +This problem is well-optimized with a monotonic stack. Further optimization is not needed. Any approach faster than O(n) is not feasible as every element must be checked at least once. |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +## 📌 Example Walkthroughs & Dry Runs |
| 94 | + |
| 95 | +```plaintext |
| 96 | +Example: |
| 97 | +Input: [1, 2, 3, 4, 3] |
| 98 | +
|
| 99 | +i=4 → 3 → stack=[], ans[4]=-1 → push 3 |
| 100 | +i=3 → 4 → pop 3, stack=[], ans[3]=-1 → push 4 |
| 101 | +i=2 → 3 → 4>3 → ans[2]=4 → push 3 |
| 102 | +i=1 → 2 → 3>2 → ans[1]=3 → push 2 |
| 103 | +i=0 → 1 → 2>1 → ans[0]=2 → push 1 |
| 104 | +
|
| 105 | +Output: [2, 3, 4, -1, 4] |
| 106 | +``` |
| 107 | + |
| 108 | +--- |
| 109 | + |
| 110 | +## 🔗 Additional Resources |
| 111 | + |
| 112 | +- [Monotonic Stack - Intuition](https://www.geeksforgeeks.org/dsa/introduction-to-monotonic-stack-2/) |
| 113 | +- [Java Stack Docs](https://docs.oracle.com/javase/8/docs/api/java/util/Stack.html) |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +Author: Abdul Wahab |
| 118 | +Date: 19/07/2025 |
0 commit comments