【力扣算法题】下一个更大的元素
文章目录
题目介绍
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
题解
1. 暴力解法(个人解法/力扣官方解法1)
第二个办法很好,可以用于积累
暴力法就很简单了,首先初始化结果数组内所有元素为-1,对于第一个数组里的每个元素,找到它在第二个数组的位置,然后顺着往后找,找到就放入结果数组,没找到就不放
C++源码:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> result(nums1.size(), -1);
int n = nums1.size();
int m = nums2.size();
for(unsigned int i = 0; i < n; i++)
{
int start = 0;
while(start < m)
{
if(nums2[start] == nums1[i])
{
start++;
break;
}
start++;
}
for(unsigned int j = start; j < m; j++)
{
if(nums2[j] > nums1[i])
{
result[i] = nums2[j];
break;
}
}
}
return result;
}
2. 单调栈解法(力扣官方解法2)
首先我们得理解,上面的暴力法哪里可以优化
很明显,我们每次循环里都会遍历一次第二个数组,如果能让我们需要检查的元素变少,就能节省大量的时间
我们从后向前倒叙进行,看完下面的图解算法你瞬间会理解单调栈对于“下一个更大”问题的解决思路
1. 首先从第7个元素开始,倒叙开始遍历
2. 遵循这个原则:在当前元素向后看,如果后面那个元素比我小,就把他从栈里挤出去,之后我自己进去。下图就是根据这个原则排除好的图
- 为什么会有这个原则?对于每个元素,我们唯一能动的,也就只有我们后面的那一个元素,它若比我们小,我们当然可以排除
- 那么?为什么只能管后面的一个,而不是再后面的?因为我们 i 没有权利去确认 i + 2是不是大于 i + 1
- 举一个简单的例子:看1, 2, 3号(第2个,第3个,第4个)元素,如果我们管的太多,那么2和3按理来说都比1小,那么我们可以安全的把2和3都排除吗?当然不能!因为2后面的第一个更大的元素刚好就是3,如果排除了3,那么我们将得到错误的结果4
- 所以,记住,单调栈的原则就是不能自私,只能决定自己的事,不能管太多
3. 这样下来,对于被排除的选项已经不用看了,栈里剩下的内容就是所有可能的答案
思想就讲这么多,代码还是得弄上来
C++源码:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> hashmap;
stack<int> st;
for (int i = nums2.size() - 1; i >= 0; --i) {
int num = nums2[i];
while (!st.empty() && num >= st.top()) {
st.pop();
}
hashmap[num] = st.empty() ? -1 : st.top();
st.push(num);
}
vector<int> res(nums1.size());
for (int i = 0; i < nums1.size(); ++i) {
res[i] = hashmap[nums1[i]];
}
return res;
}
// 作者:LeetCode-Solution
// 链接:https://leetcode-cn.com/problems/next-greater-element-i/solution/xia-yi-ge-geng-da-yuan-su-i-by-leetcode-bfcoj/