下一個更大元素

今天遇到了很有意思的一類題目,也就是標題裏說的,“下一個更大元素”。

先看看它的簡單版本:

給定兩個沒有重複元素的數組 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每個元素在 nums2 中的下一個比其大的值。

nums1 中數字 x 的下一個更大元素是指 x 在 nums2 中對應位置的右邊的第一個比 x 大的元素。如果不存在,對應位置輸出-1。

一開始看到這個題,第一反應就是HashMap(因爲我用的C++,實際上是unordered_map),建立nums2中每個元素和下標的對應關係,然後拿nums1中的值去找到下標,然後遍歷找到第一個比它大的值:

vector<int> nextGreaterElement(vector<int> &nums1, vector<int> &nums2)
{
    int length2 = nums2.size();
    unordered_map<int, int> nums2_index_map;
    for (int i = 0; i < length2; ++i)
    {
        nums2_index_map[nums2[i]] = i;
    }

    vector<int> result;
    int length1 = nums1.size();
    for (const int &target : nums1)
    {
        bool has_found = false;
        for (int i = nums2_index_map[target]; i < length2; ++i)
        {
            if (nums2[i] > target)
            {
                has_found = true;
                result.push_back(nums2[i]);
                break;
            }
        }
        if (!has_found)
        {
            result.push_back(-1);
        }
    }
    return result;
}

複雜度大概是O(kn)?反正取決於nums1的長度就是了。結果也相當不錯,歸功於HashMap本身的效率,這麼一個相當暴力的算法的速度居然能超過100%,實在是讓人失去進一步優化的動力……

按理說到這裏就可以結束了,但是我看到一個很有意思的算法,專門用來解決這一類問題,就是所謂的“單調棧”(以下來自labuladong@LeetCode,這是我看到的最好的解釋了):

vector<int> nextGreaterElement(vector<int>& nums) {
    vector<int> ans(nums.size()); // 存放答案的數組
    stack<int> s;
    for (int i = nums.size() - 1; i >= 0; i--) { // 倒着往棧裏放
        while (!s.empty() && s.top() <= nums[i]) { // 判定個子高矮
            s.pop(); // 矮個起開,反正也被擋着了。。。
        }
        ans[i] = s.empty() ? -1 : s.top(); // 這個元素身後的第一個高個
        s.push(nums[i]); // 進隊,接受之後的身高判定吧!
    }
    return ans;
}

其中有一個非常有意思的點:vector<int> ans(nums.size());。我一開始覺得沒啥用,就是直接定義了一個普通的vector,後來纔想起來,聲明大小可以避免vector在push_back的時候重新分配空間,可以提高效率。

所以做算法題的時候還是要錙銖必較啊……

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