標籤:
題目:給定(可能是負的)整數A1、A2、…、AN,求出並確定對應的序列的最大值。如果所有的整數都是負數,那麼最大連續子數列和就是0,只是求出最大值,不需要求出具體的序列,作為這個題目的變種有很多情況下給你一個確定的數列,具體求和,大同小異,共有四種解法,按照時間複雜度來解,object-c實現,解法如下:
窮舉法
這個應該是這個題目最容易想到的方式,通過迴圈遍曆出所有的序列組合,求出最大的序列的最大值,代碼如下:
-(NSInteger)maxSubsequenceSum:(NSArray *)data{ NSInteger maxSum=0;//最大子序列的和 for (NSInteger start=0; start<[data count]; start++) { for (NSInteger end=start; end<[data count]; end++) { NSInteger currentSum=0;//當前子序列的和 //data[start]~data[end]子序列的和 for (NSInteger i=start; i<=end; i++) { currentSum+=[[data objectAtIndex:i] integerValue]; } //通過判斷給最大子序列的和賦值 if (maxSum<currentSum) { maxSum=currentSum; } } } return maxSum;}
這個演算法三個迴圈,假設數組的長度為n,第一層迴圈為n,第二層迴圈n-start,第三層end-start,可算出時間複雜度O(n*n*n)=O(N^3),時間複雜度是跟輸入長度的立方有關,如果數組過長會是一個災難~
窮舉精簡版
對data[start]~data[end]子序列求和,可以由上一次求和data[start]~data[end-1]的結果加上data[end]得到,不需要重頭開始計算,時間複雜度為O(N^2)
-(NSInteger)maxSubsequenceSumSecond:(NSArray *)data{ NSInteger maxSum=0;//最大子序列的和 for (NSInteger start=0; start<[data count]; start++) { NSInteger currentSum=0;//當前子序列的和 for (NSInteger end=start; end<[data count]; end++) { //data[start]~data[end]子序列的和,通過end加入,不需要迴圈 currentSum+=[[data objectAtIndex:end] integerValue]; if (maxSum<currentSum) { maxSum=currentSum; } } } return maxSum;}遞迴版
題目中最大子序列可能在三個地方出現,左半部,右半部,跨越輸入資料的中部而佔據左右兩部分。前兩種情況遞迴求解,第三種情況的最大和可以通過求出前半部分最大和(包含前半部分最後一個元素)以及後半部分最大和(包含後半部分的第一個元素)相加而得到。
-(NSInteger)maxSubsequenceSumThird:(NSArray *)data leftIndex:(NSInteger)left rightIndex:(NSInteger)right{ if (left==right) { if (data[left]>0) { //空集也算是子序列,空集和為0,最大子序列和最小為0 return [data[left] integerValue]; }else{ return 0; } } NSInteger center=(left+right)/2; NSInteger maxLeftSum=[self maxSubsequenceSumThird:data leftIndex:left rightIndex:center]; NSInteger maxRightSum=[self maxSubsequenceSumThird:data leftIndex:center+1 rightIndex:right]; //左半部分中包含最右邊元素的子序列的最大和 NSInteger maxLeftBorderSum=0,leftBorderSum=0; for (NSInteger i=center; i>=left; i--) { leftBorderSum+=[data[i] integerValue]; if (leftBorderSum>maxLeftBorderSum) { maxLeftBorderSum=leftBorderSum; } } //右半部分包含最左邊的值 NSInteger maxRightBorderSum=0,rightBorderSum=0; for (NSInteger i=center+1;i<right;i++) { rightBorderSum+=[data[i] integerValue]; if (rightBorderSum>maxRightBorderSum) { maxRightBorderSum=rightBorderSum; } } //跨越左右部分的最大序列和 NSInteger maxMiddleSum=maxLeftBorderSum+maxRightBorderSum; //左部分,右部分,跨越左右的最大序列和的最大值 NSInteger result=maxLeftSum>maxRightSum?maxLeftSum:maxRightSum; return result>maxMiddleSum?result:maxMiddleSum;}
如果left==right,那麼T(1)=1,兩層迴圈的時間的次數2/N,最後的時間複雜度T(N)=2T(N/2)+O(N),等價於2T(N/2)+N,T(N)=N*(K+1)(這個可以自己推導),T(N)=N*(k+1)=NlogN +N=O(N );
最簡版
一次遍曆,如果小於0,重新設定迴圈的位置,時間複雜度O(N):
-(NSInteger)maxSubsequenceSumFour:(NSArray *)data{ NSInteger maxSum=0,currentSum=0; for (NSInteger index=0; index<[data count]; index++) { currentSum+=[[data objectAtIndex:index] integerValue]; //判斷當前序列的和是否為正數 if (currentSum<0) { currentSum=0; } else if(maxSum<currentSum) { maxSum=currentSum; } } return maxSum;}
還有一個極端的情況,如果都是負數,不想返回0,擷取最大的負整數即可:
-(NSInteger)maxSubsequenceSumSpecial:(NSArray *)data{ NSInteger maxSum=[[data objectAtIndex:0] integerValue],currentSum=0; NSInteger maxNegative=[[data objectAtIndex:0] integerValue]; for (NSInteger index=0; index<[data count]; index++) { currentSum+=[[data objectAtIndex:index] integerValue]; if (currentSum<0) { currentSum=0; } else if(maxSum<currentSum) { maxSum=currentSum; } if (maxNegative<[data[index] integerValue]) { maxNegative=[data[index] integerValue]; } } return maxSum>maxNegative?maxSum:maxNegative; }
調用如下:
NSArray *dataSource=[[NSArray alloc]initWithObjects:@"10",@"-9",@"-3",@"8",@"-2", nil]; MaxSubsequence *maxSubsequence=[[MaxSubsequence alloc]init]; NSInteger result=[maxSubsequence maxSubsequenceSum:dataSource]; NSLog(@"最大的連續子序列的和:%ld",(long)result); NSInteger resultSecond=[maxSubsequence maxSubsequenceSumSecond:dataSource]; NSLog(@"第二種最大的連續子序列的和:%ld",(long)resultSecond); NSInteger thirdResult=[maxSubsequence maxSubsequenceSumThird:dataSource leftIndex:0 rightIndex:dataSource.count-1]; NSLog(@"第三種最大的連續子序列的和:%ld",(long)thirdResult); NSInteger fourResult=[maxSubsequence maxSubsequenceSumFour:dataSource]; NSLog(@"第四種最大的連續子序列的和:%ld",(long)fourResult); NSInteger specialResult=[maxSubsequence maxSubsequenceSumSpecial:dataSource]; NSLog(@"第四種全是負數最大的連續子序列的和:%ld",(long)specialResult);
結果是10,數組簡單定義下,重要是看過程~
演算法-最大連續子序列和