例:求一个数组的和为0的连续最长子串
arr[]数组存放原数组,sum[]为前缀和数组,用map存储前缀和每一个数字第一次出现的下标。比如现在前缀和为10,所以要查找前缀和为-10第一次出现的位置,找道后就是前缀和为10的和为0的最长的子段。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <map> 5 6 using namespace std; 7 8 // O(n^2) 9 int longestSubArrayOfSumZero_1(const vector<int> &arr){ 10 int sz=arr.size(); 11 vector<int> preSum(sz+1,0); 12 13 for(int i=0;i<sz;i++){ 14 preSum[i+1]=preSum[i]+arr[i]; 15 } 16 17 int longest=0; 18 int start=0; 19 for(int i=1;i<=sz;i++){ 20 for(int j=0;j<i;j++){ 21 if(preSum[i]==preSum[j] && (i-j)>longest){ 22 longest=i-j; 23 start=j; 24 } 25 } 26 } 27 for(int i=start;i<start+longest;i++) 28 printf("%d",arr[i]); 29 printf("\n"); 30 return longest; 31 } 32 33 34 // O(n) 35 int longestSubArrayOfSumZero_2(const vector<int> &arr){ 36 int sz=arr.size(); 37 int longest=0; 38 map<int,int> pos; 39 int sum=0; 40 pos[sum]=0; 41 int start=0; 42 43 for(int i=0;i<sz;i++){ 44 sum+=arr[i]; 45 if(pos.find(sum)!=pos.end()){ 46 int len=i-pos[sum]+1; 47 if(len>longest){ 48 longest=len; 49 start=pos[sum]; 50 } 51 } 52 else 53 pos[sum]=i; 54 55 } 56 for(int i=start;i<start+longest;i++) 57 printf("%d",arr[i]); 58 printf("\n"); 59 return longest; 60 } 61 62 int main(){ 63 int n; 64 while(~scanf("%d",&n)){ 65 vector<int> arr(n); 66 for(int i=0;i<n;i++){ 67 scanf("%d",&arr[i]); 68 } 69 printf("%d\n",longestSubArrayOfSumZero_1(arr)); 70 printf("%d\n",longestSubArrayOfSumZero_2(arr)); 71 } 72 return 0; 73 }