標籤:
一、題目: 返回一個整數數組中最大子數組的和。 要求: 輸入一個整形數組,數組裡有正數也有負數。 數組中連續的一個或多個整數組成一個子數組,每個子數組都有一個和。 如 果數組A[0]……A[j-1]首尾相鄰,允許A[i-1], …… A[n-1], A[0]……A[j-1]之和最大。 同時返回最大子數組的位置。 求所有子數組的和的最大值。要求時間複雜度為O(n)。二、設計思路 開始想的是用鏈表實現數組首尾相連,可是由於鏈表用著不太熟悉,便想了另一種演算法:當最大值未出現跨域是就按常規方法計算找出,
出現跨域時,既然a[0] a[n-1]都出現在解
中
,則可以將其解延伸到最大,
也就是從a[0]開始,向右掃描,從a[n-1]開始向左掃描,兩者直到出現負數為止, 這樣就不會出現中間是負數,但是兩端是正數,但卻選擇整個序列的情況。三、原始碼
//趙建松、張文冬
#include <iostream.h>#include <stdlib.h>/* * 現在是數組為一個環形結構,最大連續和又該如何?? * 1.最簡單的方法:數組迴圈移位,再進行逐一求解最大連續和,演算法複雜度O(n^2) * 2.s[i][l] = s[i][l-1]+a[i+l-1]; sum = max{s[i][l]},s[i][l]:以i開始長度為l的連續和 * O(n) 的解法: * 1.解未出現跨域的情況,也就是a[0] ~ a[n-1](原問題) * 2.解出現跨域情況 a[n-1]~a[0] 出現在解的中間或邊界*/int max_subarray_bound(int a[],int from,int to){ int i,max,sum; max = a[from]; sum = a[from]; for(i = from + 1;i <= to;i++) { if(sum < 0){ sum = 0;} sum += a[i]; if(max < sum){ max = sum;} } return max;}int max_subarray_cycle(int a[],int size){ int sum,i,j,s,m; //第一種情況,未跨域 sum = max_subarray_bound(a,0,size-1); /* * 第二種情況,出現跨域,既然a[0] a[n-1]都出現在解中,則可以將其解延伸到最大, * 也就是從a[0]開始,向右掃描,從a[n-1]開始向左掃描,兩者直到出現負數為止, * 這樣就不會出現中間是負數,但是兩端是正數,但卻選擇整個序列的情況. */if(size == 2) return sum; i = 1; j = size-2; s = a[i-1] + a[j+1]; while(i < j && (a[i] >=0 || a[j] >= 0)) { if(a[i] >= 0) { s += a[i]; i++; } if(a[j] >= 0) { s += a[j]; j--; } } if(i == j) { if(a[i] >0) s+=a[i]; if(s < sum) return sum; else return s; } if(i < j) { //算出以i為頭部的所有連續子數組和或者以j為尾的連續子數組和,從而找到最大的元素 int s2,k; m = a[i]; s2 = m; for(k=i+1;k <= j;k++) { s2 += a[k]; if(m < s2) m = s2; } s2 = a[j]; for(k = j-1;k>=i;k--) { s2 += a[j]; if(m < s2) m = s2; } if(m > 0)s += m; } if(s < sum) return sum; else return s;}int main(int argc,char *argv[]){ int a[] = {5,-3,-1,5,10,11};for(int j=0;j<6;j++){cout<<a[j]<<" ";} cout<<endl<<"最大子數組和為:"<<max_subarray_cycle(a,sizeof(a)/sizeof(a[0]))<<endl; return 0;}
四、
五、體會
在實現環形數組求最大子數組的過程中,我和張文冬分別想了不一樣的方法來實現環形數組的問題,但是都存在缺陷和不容易實現的地方,最後找到了這種方法,但由於時間緊迫,功能實現的也不是特別完善,但在討論各種方法的過程中也發散了我們的思維,有了收穫。
軟體工程——結對開發環形數組