//最大子序列和問題的四種算法
//注意以下算法只是求出最大的和,並沒有找出對應的子序列
public class MaxSubSum {
public static void main(String[] args) {
int[] a = { 4, -3, 5, -2, -1, 2, 6, -2 };
System.out.println(maxSubSum1(a));
System.out.println(maxSubSum2(a));
System.out.println(maxSubSum3(a));
System.out.println(maxSubSum4(a));
}
// 算法一,窮舉法,運行時間 O(N^3)
public static int maxSubSum1(int[] a) {
int maxSum = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i; j < a.length; j++) {
int thisSum = 0;
for (int k = i; k <= j; k++)
thisSum += a[k];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
// 算法二,窮舉法的改進,與算法一沒有本質區別
// 由三層循環改爲兩層,運行時間O(N^2)
public static int maxSubSum2(int[] a) {
int maxSum = 0;
for (int i = 0; i < a.length; i++) {
int thisSum = 0;
for (int j = i; j < a.length; j++) {
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
// 算法三,採用遞歸思想和分治(divide-and-conquer)策略
// 如果把序列從中間分爲兩部分,那麼最大子序列和可能在三處出現,要麼整個出現在輸入數據的左半部,要麼整個出現在右半部,
// 要麼跨越分界線。前兩種情況可以遞歸求解,第三種情況的最大和可以通過求出前半部分(包括前半部分的最後一個元素)的最大
// 和以及後半部分(包含後半部分的第一個元素)的最大和而得到,此時將兩個和相加。
// 運行時間O(NlogN)
public static int maxSubSum3(int[] a) {
return maxSumRec(a, 0, a.length - 1);
}
private static int maxSumRec(int[] a, int left, int right) {
// 基準情況(也叫終止條件)
if (left == right)
return a[left] > 0 ? a[left] : 0;
// 分成兩個子問題
int center = (left + right) / 2;
// 遞歸求解
int maxLeftSum = maxSumRec(a, left, center);
int maxRightSum = maxSumRec(a, center + 1, right);
//左半部分最大值
int maxLeftBoardSum = 0;
int leftBoardSum = 0;
for (int i = center; i >= left; i--) {
leftBoardSum += a[i];
if (leftBoardSum > maxLeftBoardSum)
maxLeftBoardSum = leftBoardSum;
}
//右半部分最大值
int maxRightBoardSum = 0;
int RightBoardSum = 0;
for (int i = center+1; i <= right; i++) {
RightBoardSum += a[i];
if (RightBoardSum > maxRightBoardSum)
maxRightBoardSum = RightBoardSum;
}
return max3(maxLeftSum, maxRightSum, maxLeftBoardSum + maxRightBoardSum);
}
//返回三個數中最大的那個
private static int max3(int a, int b, int c){
return a >= b ? (a >= c ? a : c) : (b >= c ? b : c);
}
//算法四,最快的算法,運行時間O(N)
//核心思想:任何負的子序列不可能是最優子序列的前綴!將子序列一步步推進,遇到負的前綴就把該前綴拋棄
//該算法只對數據進行一次掃描,使得數據可以按順序讀入,在主存中不必存儲數組的任何部分。在任意時刻,算法都能對
//它已經讀入的數據給出子序列的正確答案(其他算法不行)。具有這種特性的算法叫聯機算法(on-line algorithm)
public static int maxSubSum4(int[] a){
int maxSum = 0;
int thisSum = 0;
for (int i=0; i<a.length; i++){
thisSum += a[i];
if (thisSum > maxSum)
maxSum = thisSum;
else if (thisSum < 0)
thisSum = 0;
}
return maxSum;
}
}
經典最大子序列和問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.