【演算法學習】最大子陣列問題的分治法求解
阿新 • • 發佈:2019-02-20
最大子陣列問題求解的是給定一個數組a[0...n-1],求出它的一個子陣列使得其所有元素的和加起來最大
如果使用暴力解法即列舉所有的子陣列,則時間複雜度為O(n^2)
採用分治法,對一段陣列a[low.....high],求它的最大子陣列,mid = (low+high)/ 2
那麼,a[low..high]的子陣列有可能有三種分佈的情況,假設子陣列的上下屆為i,j
1) 在a的左部分,即 low < = i <= j < = mid
2) 在a的右部分,即 mid + 1 <= i <= j <= high
3) 跨越mid,即 low <= i <= mid <= j <= high
下面給出基於此思想的分治演算法
注:要對一個數組a[0...n-1]求其最大子陣列和,呼叫的是find_max_subarray(a,0,n-1)
#include <iostream> #include <limits.h> using namespace std; struct temple { int left; int right; int sum; }; temple max_crossing_subarr ( int* a, int low, int mid, int high) { int left_sum = INT_MIN; int right_sum = INT_MIN; int sum; int max_left = low; int max_right = high; //找左邊的 sum = 0; for ( int i = mid; i >= low; --i ) { sum += a[i]; if ( sum > left_sum ) { left_sum = sum; max_left = i; } } //找右邊的 sum = 0; for ( int i = mid+1; i <= high; ++i ) { sum += a[i]; if ( sum > right_sum ) { right_sum = sum; max_right = i; } } temple t = { max_left, max_right, left_sum + right_sum }; return t; } temple find_max_subarray ( int*a, int low, int high ) { if ( high == low ) { temple t; t.left = low; t.right = high; t.sum = a[low]; return t; } else { int mid = ( high + low ) / 2; temple left_temple = find_max_subarray(a,low,mid); temple right_temple = find_max_subarray(a,mid+1,high); temple cross_temple = max_crossing_subarr(a,low,mid,high); if ( left_temple.sum >= right_temple.sum && left_temple.sum >= cross_temple.sum ) { return left_temple; } else if ( right_temple.sum >= left_temple.sum && right_temple.sum >= cross_temple.sum ) { return right_temple; } else { return cross_temple; } } } int main() { // int a[] = { 13, -3, -25, 20, -3, 16, -23, 18, 20, -7, 12 // -5, 22, 15, -4, 7}; int a[] = {-5,1,2,5,-3,7,-10}; temple t = find_max_subarray(a,0,sizeof(a)/sizeof(int)-1); cout << t.sum << endl;//結果12 return 0; }