尺取法/雙指標法
阿新 • • 發佈:2021-06-10
//瞎寫的
尺取法:通過儲存一組下標,根據條件交替挪動以求最終解。
一般用於求取有一定限制的區間個數或最短的區間,有時能把一些列舉問題從O(nlogn)(二分)優化到O(n)。
例題:
SubsequencePOJ3061
題意:給定長度為n的都是正整數的數列以及整數S。求出總和不小於S的連續子序列的長度的最小值,不存在則輸出0。
思路:先記錄下標b1=1,找到最小的下標b2使得b1->b2的子序列總和不小於S(不存在則輸出0)並記錄長度。然後將b1增加一,重複前一個過程尋找新的最小b2並計算長度,與原長度比較記錄最小值。
分析,在重複過程中我們不難發現,(b1+1)->b2序列的總和必定小於S,故我們沒有必要重新列舉(b1+2)->b2的點,可以保證新的下標b2大於原先的b2。
思路程式碼表現:
void solve() { int l=1,r=n,ans=n+1,sum=0; while(1) { while(r<=n&&sum<S)sum+=a[r++]; if(sum<S)break; ans=min(ans,r-l);//r在遞迴時會到最小情況+1的位置 sum-=a[l++]; } if(ans>n)ans=0; cout<<ans<<endl; }
Jessica's Reading Problem POJ3320
題意:給定長度為n的數列,數列值可能有重複。求出現過所有元素值的子序列的最小長度。
思路:其實相同,只是判斷的條件變成了所有元素是否都出現過。
思路程式碼表現:
void solve() { int l=1,r=n,cnt=0,ans=n+1; map<int,int>mp; while(1) { while(r<=n&&sum<n) { if(!mp[a[r++]]) { mp[a[r++]]++; cnt++; } } if(cnt<n)break; ans=min(ans,r-l); if(mp[a[l++]]==1) { mp[a[l++]]--; cnt--; } } cout<<ans<<endl; }
//水了一篇