1. 程式人生 >實用技巧 >其它 >[每日一題]Leetcode496. 下一個更大元素 I和Leetcode503. 下一個更大元素 II

[每日一題]Leetcode496. 下一個更大元素 I和Leetcode503. 下一個更大元素 II


2021/3/6
今天的每日一題是Leetcode496. 下一個更大元素 I和Leetcode503. 下一個更大元素 II,因為是同類型的題所以就放一塊寫了。
Leetcode496. 下一個更大元素 I題意:

給你兩個 沒有重複元素 的陣列 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
請你找出 nums1 中每個元素在 nums2 中的下一個比其大的值。
nums1 中數字 x 的下一個更大元素是指 x 在 nums2 中對應位置的右邊的第一個比 x 大的元素。如果不存在,對應位置輸出 -1 。

首先看到這道題的第一思路肯定是暴力硬解,但是我們要思考除了暴力還有沒有別的思路呢?
我們考慮如下情況:有陣列[4,3,2,1,5],我們計算4,3,2,1這些元素的時候因為後一個數比前一個數小,所以我們都要等大於它們的數出現。當5出現的時候4,3,2,1這幾個數的後一個最大元素都是5,所以我們可以先不急著找比它們大的數,當比它們大的數出現的時候再統一處理。顯然我們可以考慮用一個棧來把它們存下來,這就是單調棧(單調棧是說棧裡面的元素從棧底到棧頂是單調遞增或者單調遞減的)。
當我們遍歷時會出現以下幾種情況:
1.棧為空,那麼就直接入棧。
2.如果當前元素比棧頂元素大:說明當前元素是前面一些元素的「下一個更大元素」,則逐個彈出棧頂元素,直到當前元素比棧頂元素小為止。
3.如果當前元素比棧頂元素小:說明當前元素的「下一個更大元素」與棧頂元素相同,則把當前元素入棧。

這一題我們可以先求出所有nums2中元素的下一個更大元素,因為沒有重複元素所以可以使用一個map對映到nums1中來減少複雜度。
c++參考程式碼:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
      stack<int> st;
      map<int,int> mp;
       int n=nums2.size();
       for(int i=0;i<n;i++)
       {
             while(!st.empty()&&nums2[i]>st.top())
             {
              mp[st.top()]=nums2[i];
               st.pop();
            }
               st.push(nums2[i]);
       }
       while(!st.empty())//注意最大值的下一最大元素是-1
        {                //最大值會一直在棧中所以需要最後處理
            mp[st.top()]=-1;
             st.pop();
        }
       vector<int> ans;
       for(int i=0;i<nums1.size();i++)
       {
           ans.push_back(mp[nums1[i]]);
       }
       return ans;
    }
};

[每日一題]Leetcode496. 下一個更大元素 I和Leetcode503. 下一個更大元素 II

Leetcode503. 下一個更大元素 II題意:

給定一個迴圈陣列(最後一個元素的下一個元素是陣列的第一個元素),輸出每個元素的下一個更大元素。數字 x 的下一個更大的元素是按陣列遍歷順序,這個數字之後的第一個比它更大的數,這意味著你應該迴圈地搜尋它的下一個更大的數。如果不存在,則輸出 -1。

和上一題一樣也是單調棧問題,但是不同的是題目說給出的陣列是迴圈陣列,何為迴圈陣列?就是說陣列的最後一個元素下一個元素是陣列的第一個元素,形狀類似於環。
我們可以把陣列複製一份到陣列末尾,這樣雖然不是嚴格的迴圈陣列,但是對於本題已經足夠了,因為本題對陣列最多遍歷兩次。然後再使用使用取模運算,可以把下標 i 對映到陣列 nums 長度的 0 - N內。
c++參考程式碼:

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
       stack<int> st;
       int n=nums.size();
       vector<int> ans(n,-1);
       for(int i=0;i<n*2-1;i++)
       {
             while(!st.empty()&&nums[i%n]>nums[st.top()])
             {
              ans[st.top()]=nums[i%n];
               st.pop();
            }
               st.push(i%n);
       }
       return ans;
    }
};

[每日一題]Leetcode496. 下一個更大元素 I和Leetcode503. 下一個更大元素 II


參考資料
·負雪明燭《動畫講解:單調棧》