原題是一個一維模式識別的題:求n個浮點數向量中連續若干個子向量中的最大和。
在書中共討論了四種算法:
第一種算法是最笨的辦法,利用三重循環求出每一個子向量的和,然後求出其中的最大值,其時間複雜度爲O(n3)
int maxvect(int *x,int n) { int maxsofar=0; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { sum=0; for(int k=i;k<=j;k++) { sum+=x[k]; } maxsofar=max(maxsofar,sum); } } return maxsofar; }
第二種算法分了兩種,其一是在求x[1…i]時利用x[1…i-1]的值,則減少了一層內循環,第二種是將計算的和的子向量存儲在一個數組中,又可稱爲累積表,這樣每個子向量的和都可由累計表中兩項相減得到。這兩種算法的時間複雜度都是O(n2)
第一種:
int maxvect(int *x,int n)
{
int maxsofar=0;
for(int i=0;i<n;i++)
{
sum=0;
for(int j=0;j<n;j++)
{
sum+=x[j];
maxsofar=max(maxsofar,sum);
}
}
return maxsofar;
}
第二種:
int maxvect(int *x,int n)
{
int maxsofar=0;
int *cumarr=new int[n+1];
cumarr[0]=0;
for(int i=0;i<n;i++)
{
cumarr[i+1]=cumarr[i]+x[i];
}
for(int i=0;i<n;i++)
{
sum=0;
for(int j=i;j<n;j++)
{
sum=cumarr[j+1]-cumarr[i];
maxsofar=max(maxsofar,sum);
}
}
return maxsofar;
}
第三種算法爲分治算法,即分別求兩個子向量的最大和,然後在劃分,最後合併起來,它的時間複雜度爲O(nlogn),在《算法導論》也提到了使用分治算法解這個題的詳細分析過程。其時間複雜度爲O(nlogn)。
int MaxSubSum2(int num[], int start, int end)//O(nlog(n))
{
int res;
if (start == end)
{
if (num[start] > 0)
return num[start];
else
return 0;
}
int mid = (start+end)/2;
int maxleftsum = MaxSubSum2(num,start,mid);
int maxrightsum = MaxSubSum2(num, mid+1, end);
res = maxleftsum > maxrightsum ? (maxleftsum) : (maxrightsum);
int leftboder = mid;
int leftbodersum = 0, leftsum = 0;
while (leftboder >= start)
{
leftsum +=num[leftboder];
if (leftsum > leftbodersum)
leftbodersum = leftsum;
leftboder--;
}
int rightboder = mid+1;
int rightbodersum = 0, rightsum = 0;
while (rightboder <=end)
{
rightsum += num[rightboder];
if (rightsum > rightbodersum)
rightbodersum = rightsum;
rightboder++;
}
int maxcentersum = rightbodersum + leftbodersum;
if (maxcentersum > res)
res = maxcentersum;
return res;
}
第四種算法掃描算法。它的思想是隻掃描一次,記下遇到的子向量的總和最大的子向量,它的問題是如何有X[0…i-1]擴展爲X[0…i],,它的做法是設立一個結束標誌maxending,它的時間複雜度爲O(n)
int maxvect(int *x,int n)
{
int maxsofar=0;
int maxendnig=0;
for(int i=0;i<n;i++)
{
maxending=max(maxending+x[i],0);
maxsofar=max(maxsofar,maxending);
}
}
return maxsofar;
}
在實際比較幾種算法的運行時間時,我非常直觀的體會的算法對於程序運行性能的影響。我用了10000個數的數組,第四種算法幾乎瞬間完成,而第一種算法就需要若干分鐘,具體性能比較我沒有截圖,不過《編程珠璣》第8章有詳細的對比,有興趣的查看,數據量越大,這種差距越大。
最後書中總結了幾種算法設計的技術:
1.保存中間狀態,避免重複計算。
2.預處理數據,存入一個結構中,如算法2中的累計表,是非常常用的一個手段。
3. 分治算法。
3. 掃描算法。利用X[0…i],擴展到X[0…i+1]