數組小技巧
阿新 • • 發佈:2018-12-23
連續 pac 如果 min 順序 一個 假設 == 子序列和
問題一:在一個數組中找到差值最大的兩個數字,要求小數在前大數在後,時間O(n)
想法:從前往後遍歷的時候記錄最大值和最小值,如果當前最大值在最小值的後面,更新差值的最大值
1 #include <algorithm> 2 #include <iostream> 3 #include <vector> 4 #include <cstdio> 5 6 using namespace std; 7 8 int readint(){ 9 int x;scanf("%d",&x);return x;10 } 11 12 int main() 13 { 14 vector<int>a; 15 int n,maxn,minn,value_maxn; 16 scanf("%d",&n); 17 for(int i=0;i<n;i++){ 18 a.push_back(readint()); 19 } 20 for(int i=0;i<n;i++){ 21 if(i==0){ 22 maxn=minn=a[i]; 23 value_maxn=0; 24 } 25 26 if(a[i]<minn){ 27 maxn=minn=a[i]; 28 } 29 if(a[i]>maxn){ 30 maxn=a[i]; 31 if(maxn-minn>value_maxn) 32 value_maxn=maxn-minn; 33 } 34 } 35 printf("%d\n",value_maxn); 36return 0; 37 }
問題二:求和最大的子序列之和(hdu1003)
想法一:首先,考慮暴力的方法,遍歷整個序列,假定所有位置都是一個開始位置,然後去求當前開始位置下,任意結束位置的序列和,比較出最大的序列和即可。這樣,時間復雜度為O(n^2)
進一步考慮,假設已經得到最大和的子序列,那麽之所以這個子序列不包含前面的幾個或者後面幾個元素的原因,就是因為前面(或者後面)連續幾個元素的和是負數。這樣,考慮子序列的結束位置,遍歷0...n-1,假設當前位置為結束位置,那麽如果以前面一個位置為結束的最大子序列和為負數時,只包含當前位置元素的子序列就是以當前位置結束的子序列的最大值;否則,以前面一個位置為結束的最大子序列和加上當前元素就是以當前位置結束的子序列的最大值。這樣,按順序遍歷一遍,就可以得到以每個位置為結束位置的最大子序列的和,其中最大的就是整個序列最大子序列的和,時間復雜度O(n)。
想法二:前綴和的想法,首先求出前綴和,一段子序列的和就變成了前綴和序列中兩值之差,求出最大的差值即可。就轉化成了問題一:如何在O(n)的時間中求出前小後大差值最大的兩個數。
1 #include <algorithm> 2 #include <iostream> 3 #include <vector> 4 #include <cstdio> 5 6 using namespace std; 7 8 int readint(){ 9 int x;scanf("%d",&x);return x; 10 } 11 12 int main() 13 { 14 vector<int>a; 15 vector<int>sum; 16 int n,maxn,minn,value_maxn; 17 scanf("%d",&n); 18 for(int i=0;i<n;i++){ 19 a.push_back(readint()); 20 } 21 for(int i=0;i<n;i++){ 22 if(i==0)sum.push_back(a[i]); 23 else sum.push_back(a[i]+sum[i-1]); 24 } 25 for(int i=0;i<n;i++){ 26 if(i==0){ 27 maxn=minn=sum[i]; 28 value_maxn=0; 29 } 30 31 if(sum[i]<minn){ 32 maxn=minn=sum[i]; 33 } 34 if(sum[i]>maxn){ 35 maxn=sum[i]; 36 if(maxn-minn>value_maxn) 37 value_maxn=maxn-minn; 38 } 39 } 40 printf("%d\n",value_maxn); 41 return 0; 42 }
問題三:求積最大的連續子段
想法:這個問題也有兩種做法,1,你可以模仿問題二的第一種做法維護最大最小值。2,模仿問題二的第二個想法,維護前綴積數組。在這裏不給出實現。
數組小技巧