给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
本题可以使用单调栈在O(n)复杂度下解决。
分析题意,可以知道我们要找到每一个数之后第一个大于它的数,那么我们可以建立一个单调递减栈,遍历输入数组,设当前即将入栈的数为nums[i],判断当前栈顶的数是否小于nums[i],如果小于,则弹出栈顶元素,并且在结果数组里给相应位置赋值nums[i],继续判断,直到栈内元素都小于nums[i],然后入栈。
先看代码:
class Solution { public: vector<int> nextGreaterElements(vector<int>& nums) { int nums_len = nums.size(); stack<int> s; vector<int> res(nums_len,-1); for(int i = 0 ; i < nums_len * 2 - 1 ; i++) { while(!s.empty()&&nums[s.top()]<nums[i%nums_len]){ res[s.top()] = nums[i%nums_len]; s.pop(); } s.push(i%nums_len); } return res; } };
思考过程:
分析while,可以发现第一个元素是直接跳过while,直接入栈的,而且保存在栈内的不是元素大小,而是元素在nums中的下标,又由于是循环数组,所以取了模。
分析例子[1,2,1]
当 i = 0 时,因为栈为空,while直接跳过,s.push(0%nums_len) 此时 s = [0] ; res = [-1,-1,-1];
当 i = 1 时,因为nums[s.top()] 也就是nums[0] 小于 nums[1%nums_len] 也就是nums[1] ,所以 res[0] = nums[1] = 2; 此时 s = [ 1 ] , res = [2,-1,-1];
当 i = 2 时,因为nums[s.top()]也就是nums[1] 等于 nums[2] ,所以此时 s = [1,2] , res = [2,-1,-1] ;
当 i = 3 时,因为nums[s.top()]也就是nums[2] 等于 nums[3%nums_len] 也就是nums[0] 所以此时 s= [1,2,0] ,res = [2,-1,-1]
当 i = 4 时,因为nums[s.top()]也就是nums[0] 小于nums[4%nums_len] 也就是nums[1] ,所以res[s.top()] = res[0] = nums[1] = 2 ; 此时s = [1,2],res = [2,-1,-1];
然后继续循环,因为res[2] 小于 nums[1] ,所以res[2] = nums[1] = 2; 此时 s = [1] , res = [2,-1, 2];
...
暴力法也写了:
class Solution { public: vector<int> nextGreaterElements(vector<int>& nums) { int nums_len = nums.size(); vector<int> ans; for(int i = 0 ; i < nums_len ; i++) { int ind = i; int maxn = -1; int flag = 1; for(int j = ind ; j < nums_len ; j++) { if(nums[j] > nums[i]) { maxn = nums[j]; flag = 0; break; } } if(flag){ for(int j = 0 ; j < ind ; j++) { if(nums[j] > nums[i]) { maxn = nums[j]; break; } } } ans.push_back(maxn); } return ans; } };