maximum-subarray
1.题目描述
输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。
2.算法分析与实现
设currSum(i)为前i个元素中,以第i个元素为结尾,和最大的连续子数组的和。那么可得一下递推公式
currSum(i+1) = currSum(i) + a(i) (currSum >= 0)
a(i) (currSum < 0)
以上公式很好理解,对于currSum(i+1)来说,等于currSum(i)加上 a[i],但如果currSum(i) < 0,加上一个负数的话,一定会比不加小,所以索性不加
那么求数组a[n]的最大子数组的问题,就转化成在Max (currSum(i)) (1<= i <=size)
基于以上的算法思想,总结出以下两实现方法
1.方法一
此实现中的借用一个辅助的数组currSum[n],currSum[i]代表以i个元素为结尾的所有子数组中的最大和
首先遍历数组a[n],得到currSum[n],然后遍历数组currSum[n],找到所有元素中找到最大的那个即可
1 // Author : Jincheng 2 // Date : 170315 3 // Description : find max sum of subarray by DP method 4 // Complexity : Time O(n) Space O(n) 5 6 #include <iostream> 7 using namespace std; 8 9 template <typename T> 10 void Print(T *a,int size); 11 12 template <typename T> 13 void MaxSumSubarray(T *a,int size) 14 { 15 T *currSum = new T[size+1]; // 辅助数组 16 currSum[1] = a[1]; 17 T maxSum ; // 全局的最大值 18 for(int i = 2;i <= size;i++) 19 { 20 if(currSum[i-1] < 0) 21 { 22 currSum[i] = a[i]; 23 } 24 else 25 { 26 currSum[i] += a[i]; 27 } 28 } 29 maxSum = [1]; 30 for(int i = 2;i<=size;i++) 31 { 32 if(maxSum < currSum[i]) 33 { 34 maxSum = currSum[i]; 35 } 36 } 37 cout << "the max sum of subarray is " << maxSum << endl; 38 39 delete b; 40 } 41 42 int main() 43 { 44 int a[] = {0,-1,-2,-7,-8,-5}; 45 Print(a,5); 46 MaxSumSubarray(a,5);
47 return 0; 48 } 50 51 template <typename T> 52 void Print(T *a,int size) 53 { 54 for(int i=1;i <= size;i++) 55 56 cout << "a[" << i << "] = " << a[i] << endl; 57 }
2.方法二
此方法是方法一的优化。
在方法一中:
首先需要一个辅助的数组currSum[n]用来保存以第i个元素结尾的最大子数组和
并且需要对a[n]进行遍历得到currSum[n],然后在对currSum[n]进行遍历得到maxSum
通过观察发现我们没必要保存所有的currSum(i),在遍历a[n]时,在求currSum(i)时,我们只需要知道currSum(i-1)就可以了
所以在方法二中 :
只需要一个变量currSum用来保存上次求得的最大和
只需要对a[n]进行一次遍历,在遍历时同时更新currSum和maxSum
1 // Author : Jincheng 2 // Date : 170315 3 // Description : find max sum of subarray by DP method 4 // Complexity : Time O(n) Space O(1) 5 6 #include <iostream> 7 using namespace std; 8 9 template <typename T> 10 void Print(T *a,int size); 11 12 template <typename T> 13 void MaxSumSubarray(T *a,int size) 14 { 15 T currSum = a[1]; // 当前以第n个数为结尾的子数组最大和 16 T maxSum = currSum; // 全局的最大和 17 int begin = 1,end = 1; // 最大子数组的开始和结尾 18 int temp = 1; 19 for (int i = 2;i <= size;i++) 20 { 21 if(currSum > 0) 22 { 23 currSum = currSum + a[i]; 24 } 25 else 26 { 27 currSum = a[i]; 28 temp = i; 29 } 30 if(currSum >= maxSum) 31 { 32 maxSum = currSum; 33 begin = temp; 34 end = i; 35 } 36 } 37 cout << "Max sum of subarray begin :" << begin << ", end : " << end << ",the sum is " << maxSum << endl; 38 } 39 40 int main() 41 { 42 int a[] = {0,-1,-2,-7,-8,-5}; 43 Print(a,5); 44 MaxSumSubarray(a,5); 45 return 0; 46 } 47 48 template <typename T> 49 void Print(T *a,int size) 50 { 51 for(int i=1;i <= size;i++) 52 53 cout << "a[" << i << "] = " << a[i] << endl; 54 }
来此一位大牛的实现
1 typedef struct { 2 unsigned left; 3 unsigned right; 4 int sum; 5 } max_subarray; 6 7 max_subarray find_maximum_subarray(int A[], unsigned low, unsigned high) { 8 max_subarray suffixes[high - low]; 9 10 suffixes[0].left = low; 11 suffixes[0].right = low + 1; 12 suffixes[0].sum = A[low]; 13 14 for (int i = low + 1; i < high; i++) { 15 if (suffixes[i - 1].sum < 0) { 16 suffixes[i].left = i; 17 suffixes[i].right = i + 1; 18 suffixes[i].sum = A[i]; 19 } else { 20 max_subarray *previous = &suffixes[i - 1]; 21 suffixes[i].left = previous->left; 22 suffixes[i].right = i + 1; 23 suffixes[i].sum = previous->sum + A[i]; 24 } 25 } 26 27 max_subarray *max = &suffixes[0]; 28 29 for (int i = low + 1; i < high; i++) { 30 if (max->sum < suffixes[i].sum) { 31 max = &suffixes[i]; 32 } 33 } 34 35 return *max; 36 }
浙公网安备 33010602011771号