LeetCode 239. Sliding Window Maximum 题解(上)

LeetCode 239. Sliding Window Maximum 题解(上)

496. Next Greater Element I 题解

一点说明
这篇博客其实是主要写 496. Next Greater Element I 题解 的。主要是这次做题过程中十分有意思。真的是巧合。 所以干脆换了种写博客的方式。 至于主标题为什么是LeetCode 239. Sliding Window Maximum 题解(上), 是因为这道题要用到我们这篇博客中所用的方法。
下面是正文。

题目描述


496. Next Greater Element I

You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1’s elements in the corresponding places of nums2.

The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.

Example 1:

Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]

Example 2:

Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]

Note:
1. All elements in nums1 and nums2 are unique.
2. The length of both nums1 and nums2 would not exceed 1000.


题目分析

首先,这是一道Easy标签的题目。 所以肯定不会很难AC。但是这题一旦数据设置大一些, 难度就上去了(例如把maxlen 设置为 107 ……
好吧, 按照通常习惯, 我们先来分析一下题目。
简单的分析就可以知道我们这题需要一个map来帮助我们优化。为什么呢? 我们需要找的是num1 对应在 num2中的元素的下一个 greater Element, 结合Note中,提到这些元素各不相同, 这里显然用一个map来建立一个映射数组下标与其储存值之间的映射。 方向应该是: value=>index
这样做之后, 其实剩下的就已经可以暴力求解了, 限制len<1000 也很显然就是为 O(n2) 算法准备的。


但是稍微想一下, 我们在暴力执行O(n2) 来找Next Greater Element 的时候, 是否进行过不必要的计算。 举个例子:
考虑这个数列: [1,3,-1,-3,5,3,6,7](如果看了主标题中的LeetCode 239. Sliding Window Maximum这道题的话,就会发现这就是那道题中的Example)
当我们寻找index=13的Next Greater Element时,我们进行循环, 会找到 index=45, 这中间加了若干个数,我们可以得到结论: 中间这些夹的数的Next Greater Element, 也是 index=45
这个结论的证明十分简单。 就不叙述了。对比之前暴力的做法, 显然剩下了这些中间数的搜索时间。

接下来我们要考虑的就是如何用数据结构实现这一方法。答案是用栈。至于这怎么想到用栈的还是偏感觉多一些, 所以也不知道怎么写~。~ 下一个Topic 就来说说用栈如何实现这一过程吧。

法一. 暴力求解。

这个方法唯一需要做的就是建立一个map来建立一个映射数组下标与其储存值之间的映射。 方向是: value=>index 。之后就对每个数循环一遍就可以找到Next Greater Element 了。复杂度为 O(n2) .
当然有一个小小改进的地方, 由于这是暴力破解, 所以没必要对于num2的每个元素去搜索, 直接搜索我们需要的就行了,即num1的元素。 这样的话复杂度为 O(nk) ,其中 n=num2.size(),k=num1.size()

法二. 用栈求解。

这个方法的核心思想前面说过了。 这里就说一下实现过程。
1. 先把第一个元素入栈。
2. 循环num2数组, 并准备依次入栈。
3. 若是当前入栈元素大于栈顶元素, 则将栈顶元素的Next Greater Element 设置为当前入栈元素, 并将栈顶元素弹出栈。
4. 重复执行3. 直到不满足3的条件。此时把当前元素入栈。
5. 循环一遍之后, 最后剩下在栈的那些元素的Next Greater Element 设置为-1.

之前的过程理解的话, 这些步骤就显然了~.~
复杂度分析:只需要扫一遍咯。。 显然就是O(n)
注意到每次扫描一个的时候可能会出现多次出栈没错, 但是出栈总数固定最大为n1 ,不会影响到复杂度的。

下面是具体代码实现:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
        unordered_map<int, int> index;
        for (int i = 0; i < nums.size(); ++i) {
            index[nums[i]] = i;
        }
        vector<int> greaterNum(nums.size(), -1);
        stack<int> s;
        for(int i = 0; i < nums.size(); ++i) {
            while (!s.empty() && nums[s.top()] < nums[i]) {
                greaterNum[s.top()] = nums[i];
                s.pop();
            }
            s.push(i);
        }
        vector<int> ans;
        for (int i = 0; i < findNums.size(); ++i) {
            ans.push_back(greaterNum[index[findNums[i]]]);
        }
        return ans;
    }
};

其他细节

  1. 利用vector构造函数能够初始赋值的特性, 可以初始先假设Next Greater Element 均为 -1, 之后可以省去步骤5的工作。
  2. 能利用unordered_map尽量不用map。复杂度貌似有差异的。

这道题其实就是实现了一个这样的功能:利用线性复杂度得到一个数组的Next Greater Element。

这题是刚好我想不到LeetCode 239. Sliding Window Maximum 这题的时候做的。 没想到刚好能用上, 真是机缘巧合。

下一篇重点讲如何将这个结论(以及方法)利用到 LeetCode 239. Sliding Window Maximum 这题上

The End.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章