我是計院出身的,但是感覺自己演算法方面比較薄弱,這些天抽些時間把以前的問題拿出來總結一下。最大子段和問題是乙個比較基礎的問題,在《資料結構與演算法:c語言實現》比較靠前的位置。為了便於說明,假設存在乙個陣列a,長度length.a和b做下標且a小於b。
演算法一
時間複雜度:o(n^3)
演算法思想:對於每乙個可能的區間[a,b]都去求其和,找到其中的最大值。
int max_sub_sum_1(const
int a, int
length)
maxsum = thissum>maxsum ? thissum : maxsum;}}
return maxsum;
}
這個演算法是最簡單粗暴的一種,也的確非常好理解。
演算法二
int max_sub_sum_2(const
int a,int
length)}}
return maxsum;
}
這演算法其實也很好理解噠~
演算法三
時間複雜度:o(n*logn)
演算法簡述:使用分治法策略。將這個陣列一分為二,則最大子段有三種情況
先看看**
int max_sub_sum_3_part(const
int a, int left, int right)
else
}center = (left + right) / 2;
leftmaxsum = max_sub_sum_3_part(a, left, center);
rightmaxsum = max_sub_sum_3_part(a, center+1, right);
//for (i = center+1; i<=right; i++)
}for (i = center; i >=left; i--)
}return
max(max(leftmaxsum, rightmaxsum), leftbordermaxsum + rightbordermaxsum);
}
//為了保持其一致性
int max_sub_sum_3(const
int a, int
length)
左半部分和右半部分的最大子段用遞迴求得,而左半部分和右半部分兼有的最大子段就需要用點小手段了。之後將三者進行比較,返回三者最大者。
其實最不好理解的部分就是遞迴的「終點」,如果當前的值大於0則返回當前值,如果小於零則返回0。這個應該怎麼考慮呢?對於當前的單位而言,有兩種選擇,選或者不選。不選則為0。
要想理解這個演算法,我覺得最重要的還是理解清楚分治的目的到底是什麼。——>求出當前範圍內的最大值。無論當前單元是多大,哪怕只有1(雖然特殊,但是目的沒有變)。
演算法四
這個演算法其實是在大二的時候就已經看到過了,但是直到今日重新看起,還是覺得很秒。尤其是和前幾個演算法對比,不光**精簡,時間複雜度也降低到了o(n)。程式設計老師所說的好的**是藝術的,這大概就是乙份好的**。
動態規劃
時間複雜度:o(n)
演算法思想:動態規劃
int max_sub_sum_4(const
int a, int
length)
else
if (thissum < 0)
}return maxsum;
}
這個方法剛看上去有些反直覺。我的第一反應就是:這真的可以得到最大子段和麼?
首先我們看一看這個問題是否符合動態規劃演算法要求的性質:
能採用動態規劃求解的問題的一般要具有3個性質:這個是肯定的,假設有兩個段,a和b且,a-b=a,則a的最大子段和就是b的最大子段和+(a或者0)。最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。
無後效性:即某階段狀態一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與當前狀態有關。如題,演算法四並沒有影響之前的狀態。
有重疊子問題:即子問題之間是不獨立的,乙個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃演算法同其他演算法相比就不具備優勢)每一次更新都要同maxsum進行比較。
thissum(n)=max(thissum(n-1)+thisnum,thisnum)
為了生成足夠大的陣列,我寫了乙個方法,可以生成一組任意大小的隨機數。為了方便之後的對比,還會把這組隨機數寫入到檔案中儲存。
#include
#include
#include
#include
#include
#define random(x) (rand()%x)
/******聲稱測試資料**************************/
int get_test_data_f(int *data, const
char* file_name, int size, int max_num)
srand((int)time(0));
for (int i = 0; i < size; i++)
return
0;}
呼叫測試的函式如下
#include "_data.h"
#include "stdlib.h"
#include "max_sub_sum.h"
#include "binary_search.h"
#define size 1000
#define max_num 200
int main()
start_time = clock();
printf("%d\n",max_sub_sum_1(a,size));
finish_time = clock();
printf("演算法1執行時間為:%d\n", (finish_time - start_time));
start_time = clock();
printf("%d\n", max_sub_sum_2(a, size));
finish_time = clock();
printf("演算法2執行時間為:%d\n", (finish_time - start_time));
start_time = clock();
printf("%d\n", max_sub_sum_3(a, size));
finish_time = clock();
printf("演算法3執行時間為:%d\n", (finish_time - start_time));
start_time = clock();
printf("%d\n", max_sub_sum_4(a, size));
finish_time = clock();
printf("演算法4執行時間為:%d\n", (finish_time - start_time));
system("pause");
return
0;}
當測試規模為1000時
當測試規模為5000時
這個時候明顯看到了演算法一和演算法二已經很吃效能了!
當測試規模打到10000時
我去minecraft燒了一片樹林才跑完,這個時候演算法一已經沒法看了。。
但是當測試規模達到了100000時呢?
求最大子列和的幾種方法
給出乙個陣列a與陣列長度n,求該陣列中最大子列和。子列由陣列中連續的元素組成 int maxsubseqsum1 int a,int n o n 3 if tempsum maxsum return maxsum int maxsubseqsum2 int a,int n o n 2 return ...
求最大子段和
給定乙個整數序列,你需要找出兩個連續子段,保證這兩個子段不能重疊,並且使得這兩個子段中所有整數的和最大。輸入描述 包含一系列的測試用例。第1行是乙個整數,表示測試用例的總數t,1 t 30 第1行後面跟了乙個空行。每個測試用例包括3行 第1行是乙個整數,表示該整數序列的長度n,2 n 5000 第2...
求最大子段和
給定乙個整數序列,你需要找到兩個連續子段,保證這兩個子段不能重疊,並且使得這兩個子段中 所有整數的和最大。輸入描述 包含一系列的測試用例,第1行是乙個整數,表示測試用例的總數t,1 t 30 每個測試用例包括3行 第1行是個整數,表示該整數序列的長度n,2 n 5000 第2行是乙個包含n個整數的序...