1. 程式人生 > >[LeetCode] Next Greater Element I 下一個較大的元素之一

[LeetCode] 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]
Explanation:
    For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
    For number 1 in the first array, the next greater number for it in the second array is 3.
    For number 2 in the first array, there is no next greater number for it in the second array, so output -1.

Example 2:

Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]
Explanation:
    For number 2 in the first array, the next greater number for it in the second array is 3.
    For number 4 in the first array, there is no next greater number for it in the second array, so output -1.

Note:

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

這道題給了我們一個數組,又給了該陣列的一個子集合,讓我們求集合中每個數字在原陣列中右邊第一個較大的數字。參考題目中給的例子,題意不難理解,既然這次難度標識為Easy,想必不是一道太難的題。二話不說,先上無腦暴力搜尋,遍歷子集合中的每一個數字,然後在原陣列中找到這個數字,然後向右遍歷,找到第一個大於該數字的數即可,參見程式碼如下:

解法一:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
        vector<int> res(findNums.size());
        for (int i = 0; i < findNums.size(); ++i) {
            int j = 0, k = 0;
            for (; j < nums.size(); ++j) {
                if (nums[j] == findNums[i]) break;
            }
            for (k = j + 1; k < nums.size(); ++k) {
                if (nums[k] > nums[j]) {
                    res[i] = nums[k];
                    break;
                }
            }
            if (k == nums.size()) res[i] = -1;
        }
        return res;
    }
};

我們來對上面的方法稍做優化,我們用雜湊表先來建立每個數字和其座標位置之間的對映,那麼我們在遍歷子集合中的數字時,就能直接定位到該數字在原陣列中的位置,然後再往右邊遍歷尋找較大數即可,參見程式碼如下:

解法二:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
        vector<int> res(findNums.size());
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); ++i) {
            m[nums[i]] = i;
        }
        for (int i = 0; i < findNums.size(); ++i) {
            res[i] = -1;
            int start = m[findNums[i]];
            for (int j = start + 1; j < nums.size(); ++j) {
                if (nums[j] > findNums[i]) {
                    res[i] = nums[j];
                    break;
                }
            }
        }
        return res;
    }
};

下面這種方法使用了雜湊表和棧,但是這裡的雜湊表和上面的不一樣,這裡是建立每個數字和其右邊第一個較大數之間的對映,沒有的話就是-1。我們遍歷原陣列中的所有數字,如果此時棧不為空,且棧頂元素小於當前數字,說明當前數字就是棧頂元素的右邊第一個較大數,那麼建立二者的對映,並且去除當前棧頂元素,最後將當前遍歷到的數字壓入棧。當所有數字都建立了對映,那麼最後我們可以直接通過雜湊錶快速的找到子集合中數字的右邊較大值,參見程式碼如下:

解法三:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
        vector<int> res;
        stack<int> st;
        unordered_map<int, int> m;
        for (int num : nums) {
            while (!st.empty() && st.top() < num) {
                m[st.top()] = num; st.pop();
            }
            st.push(num);
        }
        for (int num : findNums) {
            res.push_back(m.count(num) ? m[num] : -1);
        }        
        return res;
    }
};

類似題目:

參考資料: