这个问题可以这样抽象思考:把数组的元素想象成并列站立的人,元素大小想象成人的身高。这些人面对你站成一列,如何求元素「2」的 Next Greater Number 呢?很简单,如果能够看到元素「2」,那么他后面可见的第一个人就是「2」的 Next Greater Number,因为比「2」小的元素身高不够,都被「2」挡住了,第一个露出来的就是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
vector<int> nextGreaterElement(vector<int>& nums){ vector<int> res(nums.size()); // 存放答案的数组 stack<int> s; // 倒着往栈里放 for (int i = nums.size() - 1; i >= 0; i--) { // 判定个子高矮 while (!s.empty() && s.top() <= nums[i]) { // 矮个起开,反正也被挡着了。。。 s.pop(); } // nums[i] 身后的 next great number res[i] = s.empty() ? -1 : s.top(); // s.push(nums[i]); } return res; }
这就是单调队列解决问题的模板,其他的情况都是从这个模版修改的。for 循环要从后往前扫描元素,因为我们借助的是栈的结构,倒着入栈,其实是正着出栈。while 循环是把两个「个子高」元素之间的元素排除,因为他们的存在没有意义,前面挡着个「更高」的元素,所以他们不可能被作为后续进来的元素的 Next Great Number 了
右侧最近的更小的元素
这种情况和上一种情况相比,就是while循环的判断条件修改了从小于等于变为大于等于。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
vector<int> nextGreaterElement(vector<int>& nums){ vector<int> res(nums.size()); // 存放答案的数组 stack<int> s; // 倒着往栈里放 for (int i = nums.size() - 1; i >= 0; i--) { // 判定个子高矮 while (!s.empty() && s.top() >= nums[i]) { // 高个起开,挡着我。。。 s.pop(); } // nums[i] 身后的 next small number res[i] = s.empty() ? -1 : s.top(); // s.push(nums[i]); } return res; }
左侧
左侧最近的更大的元素
与右侧相比,for循环是从左侧开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
vector<int> nextGreaterElement(vector<int>& nums){ vector<int> res(nums.size()); // 存放答案的数组 stack<int> s; // 倒着往栈里放 for (int i = 0; i < nums.size(); i++) { // 判定个子高矮 while (!s.empty() && s.top() <= nums[i]) { // 矮个起开,反正也被挡着了。。。 s.pop(); } // nums[i] 身后的 next great number res[i] = s.empty() ? -1 : s.top(); // s.push(nums[i]); } return res; }
左侧最近的更小的元素
这种情况和上一种情况相比,就是while循环的判断条件修改了从小于等于变为大于等于。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
vector<int> nextGreaterElement(vector<int>& nums){ vector<int> res(nums.size()); // 存放答案的数组 stack<int> s; // 倒着往栈里放 for (int i = 0; i < nums.size(); i++) { // 判定个子高矮 while (!s.empty() && s.top() >= nums[i]) { // 高个起开,挡着我。。。 s.pop(); } // nums[i] 身后的 next small number res[i] = s.empty() ? -1 : s.top(); // s.push(nums[i]); } return res; }