leetcode 962. 最大寬度坡(座標系思路轉換+簡單DP)
阿新 • • 發佈:2018-12-30
題意:
給定一個整數陣列 A
,坡是元組 (i, j)
,其中 i < j
且 A[i] <= A[j]
。這樣的坡的寬度為 j - i
。求最大坡
思路:
簡化一下,就是找兩個數,A[I],A[J],然後當A[J]>A[I]時,找最大的J-I
初看不好下手,一個是數值上的比較,一個是座標的比較。可以想到一種暴力的思路:
遍歷每個當前的數,找之後最遠的大於當前數的數字,這樣子的時間複雜度是平方的,鐵定超時.jpg
假設對於那麼對於當前這個數A,找到了一個最遠的B滿足,有沒有比當前這個數A更好的數呢?即小於等於A並且在A的前面的位置。如果有的話,就有更好的情況了。由這一點,我們可以引發思路。我們可以記錄每一個數字最靠近起點的位置,和最靠近終點的位置。分別為clo[A],dis[A].好,這只是數字相同的情況,那我們怎麼樣考慮數字比他小的情況呢?
用一個mi[A]記錄小於等於A的數字最靠近起點的位置,那麼ma[A]其實就可以由小於A的所有數字的clo[i]得到,由一串序列,得到序列中每個位置到起點的最小值是一個簡單DP的思想。mi[i] = min(mi[i],array[i]);同理大於等於A的所有數中最靠近終點的位置也可以求出來為ma[A].對於A而言,最靠近終點的位置有了,最靠近起點的位置也有了,然後遍歷一下A就可以找到答案。
程式碼:O(n)
class Solution { public: int maxWidthRamp(vector<int>& A) { int sz = A.size(); int dis[50005],clo[50005],ma[50005],mi[50005]; memset(dis,-1,sizeof(dis)); memset(clo,-1,sizeof(clo)); memset(ma,-1,sizeof(ma)); memset(mi,-1,sizeof(mi)); for(int i=0;i<sz;i++){ if(dis[A[i]]!=-1)dis[A[i]] = max(dis[A[i]],i); else dis[A[i]] = i; if(clo[A[i]]!=-1)clo[A[i]] = min(clo[A[i]],i); else clo[A[i]] = i; } sort(A.begin(),A.end()); mi[A[0]] = clo[A[0]]; for(int i=1;i<sz;i++){ if(clo[A[i]]<mi[A[i-1]])mi[A[i]] = clo[A[i]]; else mi[A[i]] = mi[A[i-1]]; } ma[A[sz-1]] = dis[A[sz-1]]; for(int i=sz-2;i>=0;i--){ if(dis[A[i]]>ma[A[i+1]])ma[A[i]] = dis[A[i]]; else ma[A[i]] = ma[A[i+1]]; } int ans = 0; for(int i=0;i<sz;i++){ // cout<<A[i]<<" "<<ma[A[i]]<<" "<<mi[A[i]]<<endl; ans = max(ans,ma[A[i]]-mi[A[i]]); } return ans; } };
一個dalao的思路:從後往前遍歷,對於每一個數,找最靠近起點的最小數。這個最靠近起點的最小數由一個單調遞減的棧得到。
class Solution { public: int maxWidthRamp(vector<int>& A) { int ans=0; stack<pair<int,int>> sta; for(int i=0;i<A.size();i++){ if(sta.empty()||(A[i]<sta.top().first)) sta.push(make_pair(A[i],i)); } for(int i=A.size()-1;i>=0;i--){ while(!sta.empty()&&A[i]>=sta.top().first){ ans=max(ans,i-sta.top().second); sta.pop(); } } return ans; } };
emmmmm有人說,程式碼就像夏天女孩子的裙子,越短越好看.jpg