给定一个整数数组,请找出一个连续子数组,使得该子数组的和最大。输出答案时,请分别返回第一个数字和最后一个数字的下标。(如果两个相同的答案,请返回其中任意一个)
样例
给定 [-3, 1, 3, -3, 4]
, 返回[1,4]
.
想清楚这个问题这道题就差不多有解了:“什么时候更新start(第一个数字下标)和end(最后一个数字下标)?”
首先很直接的可以联想到用动态规划来做这个题,用一个vector来存每个位对应的到此位为止的最大子数组和
那么令F[n]表示为到n为止的最大子数组和,可以写出如下update公式
F[n]=max(F[n-1]+A[n], A[n])
如果是取前者,说明F[n-1]>=0, 此时end随n一起更新
如果是后者,说明F[n-1]<0,此时start和end重置为n
1 vector<int> continuousSubarraySum(vector<int> &A) { 2 // write your code here 3 int start=0,end=0,sum=0,max=A[0]; 4 vector<int> res(2,0); 5 vector<int> record; 6 record.push_back(A[0]); 7 for(int i=1;i<A.size();i++){ 8 if(record[i-1]<0){ 9 record.push_back(A[i]); 10 start=i; 11 end=i; 12 } 13 else{ 14 record.push_back(A[i]+record[i-1]); 15 end=i; 16 } 17 if(record[i]>max){ 18 max=record[i]; 19 res[0]=start; 20 res[1]=end; 21 } 22 } 23 return res; 24 }
这样做的话,空间复杂度就上去了,这方面可以优化一下
我们用sum作为一个累加器,当sum为负的话,显然我们不应该继续累加了,因为不管怎样不可能得出更大的和,start应该重置到加到sum为负的后一个数
对于end,只要sum不为负,end就跟着加到sum上的数走
1 vector<int> continuousSubarraySum(vector<int> &A) { 2 // write your code here 3 int start=0,end=0,sum=0,max=INT_MIN; 4 vector<int> res(2,-1); 5 for(int i=0;i<A.size();i++){ 6 if(sum<0){ 7 sum = A[i]; 8 start = i; 9 end=i; 10 } 11 else{ 12 sum+=A[i]; 13 end=i; 14 } 15 if(sum>max){ 16 max=sum; 17 res[0]=start; 18 res[1]=end; 19 } 20 } 21 return res; 22 }