ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DeepSeek LeetCode 503. 下一个更大元素 II Java实现

DeepSeek    LeetCode 503. 下一个更大元素 II Java实现

LeetCode 503. 下一个更大元素 II · Java 实现

题意

给定一个循环数组 nums,返回每个元素的"下一个更大元素"。若不存在则返回 -1。

与 496 题的区别:本题数组是环形的,可以绕回开头继续找。

示例:

nums = [1, 2, 1] 输出: [2, -1, 2]

· 1 → 下一个更大的 2
· 2 → 后面没有更大的(绕一圈也没有),-1
· 1 → 绕回开头找到 2


思路一:单调栈 + 数组翻倍(推荐)

核心技巧:把数组"逻辑上"翻倍成 2n 长(nums[i % n]),这样环形问题就转化为线性问题。

· 维护一个单调递减栈(存下标,栈底到栈顶对应值递减)。
· 遍历 i ∈ [0, 2n - 1],对当前值 nums[i % n]:
· 只要栈顶元素的值 小于 当前值,就说明找到了下一个更大元素,弹出并记录答案。
· 把当前下标压栈。

为什么遍历 2n - 1 就够了?
最后一位 i = 2n - 1 对应的下标是 n - 1,它的"下一个更大元素"只可能在 [n, 2n - 2] 中,正好覆盖了所有环回的可能,不需要再多走一圈。

importjava.util.ArrayDeque;importjava.util.Arrays;importjava.util.Deque;classSolution{publicint[]nextGreaterElements(int[]nums){intn=nums.length;int[]res=newint[n];Arrays.fill(res,-1);Deque<Integer>stack=newArrayDeque<>();// 存下标,栈内值单调递减for(inti=0;i<2*n-1;i++){intidx=i%n;while(!stack.isEmpty()&&nums[stack.peek()]<nums[idx]){res[stack.pop()]=nums[idx];}stack.push(idx);}returnres;}}

注意:2n - 1 次遍历中,前 n 次是正常入栈,后 n - 1 次的作用只是查找、弹出,并不是真的再把下标压进去(其实压了也没关系,因为后面不会再被用到,只是栈会变长一点点)。如果你写 2 * n 也完全正确,只是多一次冗余判断。


思路二:暴力 O(n²)(仅作对照)

classSolution{publicint[]nextGreaterElements(int[]nums){intn=nums.length;int[]res=newint[n];for(inti=0;i<n;i++){res[i]=-1;for(intj=1;j<n;j++){intidx=(i+j)%n;if(nums[idx]>nums[i]){res[i]=nums[idx];break;}}}returnres;}}

· 时间 O(n²),会被大数据卡住,只适合理解题意。


思路三:Deque 存值 + 下标映射(不推荐)

有人会尝试 Map<value, value> 映射。因为数组有重复元素,value → next greater 映射会冲突,所以必须用下标入栈,这是本题的坑点之一。


复杂度

方法 时间 空间
单调栈(推荐) O(n) O(n)
暴力 O(n²) O(1)

每个下标最多入栈、出栈各一次,所以栈版本的总操作数是 O(n)。


关键坑点 ⚠️

  1. 必须用下标入栈,不能用值
    · 数组里可能有重复元素(如 [2, 2, 3]),用 Map<Integer, Integer> 做映射会覆盖。
    · 用下标才能唯一确定位置。
  2. 循环长度是 2 * n - 1,不是 2 * n
    · 2n 也能对,但 2n - 1 更"紧",是面试官爱问的细节。
    · 原因:最后一个元素 (n-1) 的下一个更大元素只可能在 [n, 2n-2] 里出现,2n-1 这一位多余。
  3. 比较必须是 <,不能是 <=
    · 相等不算"更大",相等时不能弹出。
    · 写成 <= 会导致 [2,2,3] 的前两个 2 错误地指向彼此。
  4. res 初始化为 -1,而不是 0
    · 0 也未必是合法答案,正确默认值只能是 -1(题意:不存在则 -1)。
  5. ArrayDeque 不允许 push(null)
    · 用 Deque 存下标(自动装箱),不会出问题;但别尝试 push(null)。
  6. 不要真的构造一个 2n 长的数组
    · 用 i % n 取模即可,既省空间又符合"环形"语义。

一句话总结

环形问题 = 遍历两圈 + 取模,用单调栈在 2n - 1 次遍历中"出栈即找到答案"。栈存下标(防重复值),比较用严格 <,答案默认 -1。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进