LeetCode 496简单单调栈
下一个更大元素 I 图解题解
这道题到底在问什么
nums1 = [4,1,2],nums2 = [2,1,5,6,3,8,4,7]。对 nums1 每个数,在 nums2 中定位后向右找第一个更大的数。
- 输入
- nums1=[4,1,2], nums2=[2,1,5,6,3,8,4,7]
- 输出
- [7,5,5]
最优解:一步一步想明白
- 3记住这句,下面每一帧都在演它。
- 4轮到 nums2[0] = 2,先看它能不能把栈里的小数顶出去。
- 5没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 6轮到 nums2[1] = 1,先看它能不能把栈里的小数顶出去。
- 7没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 8轮到 nums2[2] = 5,先看它能不能把栈里的小数顶出去。
- 9当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 10当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 11没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 12轮到 nums2[3] = 6,先看它能不能把栈里的小数顶出去。
- 13当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 14没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 15轮到 nums2[4] = 3,先看它能不能把栈里的小数顶出去。
- 16没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 17轮到 nums2[5] = 8,先看它能不能把栈里的小数顶出去。
- 18当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 19当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 20没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 21轮到 nums2[6] = 4,先看它能不能把栈里的小数顶出去。
- 22没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 23轮到 nums2[7] = 7,先看它能不能把栈里的小数顶出去。
- 24当前数比栈顶大:栈顶等到了它的下一个更大,弹出并记进哈希。继续看还能不能弹。
- 25没人能再被它弹了(栈顶≥它或栈空),它自己入栈,递减栈结构保持。
- 26扫描结束,栈里残留的 7 右边没有更大的数,它的下一个更大记 -1。
- 27扫描结束,栈里残留的 8 右边没有更大的数,它的下一个更大记 -1。
⚠️ 容易写错的地方
✗ 错:对 nums1 逐个暴力右扫
✓ 对:只对 nums2 单调栈一遍 + 哈希
暴力 O(n·m),单调栈摊还 O(n)
✗ 错:栈存下标还是存值搞混
✓ 对:本题存值即可(直接当哈希 key)
nums2 元素互不相同
✗ 错:忘记栈中残留记 -1
✓ 对:扫完后剩在栈里的都没有更大的数
它们右边再无更大值
完整代码(Python / C++ / Java)
Python
def nextGreaterElement(nums1, nums2):
greater, stack = {}, []
for x in nums2:
while stack and stack[-1] < x:
greater[stack.pop()] = x # 栈顶的下一个更大 = x
stack.append(x)
return [greater.get(v, -1) for v in nums1]C++
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2){
unordered_map<int,int> g; stack<int> st;
for(int x : nums2){
while(!st.empty() && st.top() < x){ g[st.top()] = x; st.pop(); }
st.push(x);
}
vector<int> res;
for(int v : nums1) res.push_back(g.count(v) ? g[v] : -1);
return res;
}Java
public int[] nextGreaterElement(int[] nums1, int[] nums2){
Map<Integer,Integer> g = new HashMap<>();
Deque<Integer> st = new ArrayDeque<>();
for(int x : nums2){
while(!st.isEmpty() && st.peek() < x) g.put(st.pop(), x);
st.push(x);
}
int[] res = new int[nums1.length];
for(int i = 0; i < nums1.length; i++) res[i] = g.getOrDefault(nums1[i], -1);
return res;
}复杂度
时间
O(n+m)
nums2 每个数最多入栈出栈一次 + 查 nums1
空间
O(n)
哈希表 + 单调栈
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 下一个更大元素 I 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
如果是环形数组(LC503)怎么办?+
把数组逻辑上拼成两倍长(下标取模),遍历 2n 次,单调栈逻辑不变。
为什么单调栈能摊还到 O(n)?+
每个元素最多入栈一次、出栈一次,总操作数 O(n),虽然内层有 while 但整体线性。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 下一个更大元素 I 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。