题目描述
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
难度:中等
注意: 输入数组的长度不会超过 10000。
思路分析
解题流程
-
分析描述及结合示例:找到比目标元素大的下一个元素。
// 当前元素 let target = nums[i] -
给定是一个
循环数组, 按顺序在目标值后的元素和目标值前的元素中查找。 -
数据
slice方法截取前、后的元素合并后,在其中查找// 待查找数据 let detectNums = nums.slice(i+1).concat(nums.slice(0,i)) -
找到比目标值得元素,则加入结果值中
result中,没有则添加-1到result中。 -
循环结束后返回
result.
单调栈优化解题流程:
-
循环数组,通过复制数组,取值时
i%len去到对应的值。 -
栈中记录每个入栈的元素的下标。
-
若栈不为空, 则每次取栈尾元素
nums[stack[stack.length - 1]]和目标元素做nums[i%len]对比, -
如果栈尾元素小于目标元素,则说明栈尾下标指向的元素的下一个最大元素找到了为
target,将result[stack[stack.length - 1]] = target更新。
AC代码
-
简单思路实现的逻辑代码,通过了但是耗时、内存占用都比较大(暴力破解法)
/** * @param {number[]} nums * @return {number[]} */ var nextGreaterElements = function(nums) { let result = [] let len = nums.length; let i = 0; while(i<len){ // 被检测元素 let target = nums[i] // 检测数据 let detectNums = nums.slice(i+1).concat(nums.slice(0,i)) // 排序找出最大元素 , 然后去最大元素 // detectNums.sort() // 目标结果值 // let targetResult = detectNums[detectNums.length - 1] // 下一最大值, 不是最大值 let targetResult = detectNums.find(val=>val>target) // targetResult>target?result.push(targetResult):result.push(-1) targetResult!==undefined?result.push(targetResult):result.push(-1) i++ } return result }; -
根据题目题目的标签提示单调栈来优化代码,参考官方题解,理解解题思想。
/** * @param {number[]} nums * @return {number[]} */ var nextGreaterElements = function(nums) { let len = nums.length // 结果值 默认都为 -1 ,待找到下一个更大值时替换 let result = new Array(len).fill(-1) // 栈 let stack = [] for(let i=0;i<len*2;i++){ let target = nums[i%len] while(stack.length>0 && target>nums[stack[stack.length - 1]]){ result[stack[stack.length - 1]] = target stack.pop() } if(i<len) stack.push(i) } return result };
总结
-
第一次提交失败,没有考虑到
find函数查找不到的时候返回undefined. 导致在用例中有负数以及0时,结果值targetResult为 0时,三元表达值判定失败。 -
数组方法的使用
slice(start,end)不包含end位置上的数据;find函数找不到数据时返回undefined. -
单调栈 解题思想的理解。