1.概念
求数组的和最大的非空连续子数组,这样的连续的子数组称为最大子数组(maximum subarray)
2.常规方法(O^3)
/* 最大子段和问题 O^3*/ #include <iostream> using namespace std; //打印数组 void printArray(int *arr, int strat, int last) { for (int i = strat; i <= last; i++) { cout << arr[i] << " "; } cout << endl; } //求最大子段和 int MaxSum(int len, int *arr, int& besti, int &bestj) { int sum = 0; for(int i = 1; i <= len; i++) { for (int j = i; j <= len; j++) { int thissum = 0; for (int k = i; k <= j; k++) { thissum += arr[k]; } if (thissum > sum) { sum = thissum; //最大字段和 besti = i; //最大子段和开始位置 bestj = j; //最大子段和结束位置 } } } return sum; } int main() { int len = 0, i = 0, j = 0; int array[16] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 }; //数组长度 len = sizeof(array) / sizeof(*array); //打印原始数组 cout << "The Array is: " << endl; printArray(array, 0, len-1); //求最大子段和 cout << "The MaxSum is: " << endl; cout << MaxSum(len, array, i, j) << endl; //打印最大子段 cout << "The MaxSumArray is: " << endl; printArray(array, i, j); system("pause"); return 0; } /* The Array is: 13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7 43 The MaxSumArray is: 18 20 -7 12 请按任意键继续. . . */
3.分治策略解决最大子段和问题(nlgn)
分治策略在每层递归时都有三个步骤:
A 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。
B 解决这些子问题,递归地求解各子问题。然而,若子问题的规模足够小,则直接求解。
C 合并这些子问题的解成原问题的解。
分治策略的求解分析
假设要寻找子数组A[low…high]的最大子数组。使用分治策略要将子数组划分为两个规模尽量相等的子数组。先找到中间位置mid,然后考虑求解两个子数组A[low…mid]和A[mid+1…high]。
A[low…high]的任何连续子数组A[i…j]所处的位置必然是以下三种情况之一:
A 完全位于子数组A[low…mid]中,low≤i≤j≤mid。
B 完全位于子数组A[mid+1…high],mid+1≤i≤j≤high。
C 跨越了中点,low≤i≤mid≤j≤high。
/* 分治思想下的最大子段和问题 nlgn*/ #include <iostream> using namespace std; //打印数组 void PrintArray(int *arr, int strat, int last) { for (int i = strat; i <= last; i++) { cout << arr[i] << " "; } cout << endl; } //寻找最大子段和 int MaxSubSum(int *arr, int low, int high, int& bestl, int& bestr) { int sum = 0, mid = 0, leftSum = 0, rightSum = 0; int sl = 0, sr = 0, leftS = 0, rightS = 0; int l = 0, r = 0; if (low == high)//只有一个元素 { sum = arr[low]; } else { mid = (low + high) / 2;//中间位置 //分治思想 leftSum = MaxSubSum(arr, low, mid, l, r); rightSum = MaxSubSum(arr, mid + 1, high, l, r); //左半部分最大子段和 for (int i = mid; i >= low; i--) { leftS += arr[i]; if (leftS > sl) { sl = leftS; bestl = i; } } //右半部分最大子段和 for (int i = mid + 1; i <= high; i++) { rightS += arr[i]; if (rightS > sr) { sr = rightS; bestr = i; } } sum = sl + sr;//跨越中点的最大子段和 if (sum < leftSum) { sum = leftSum; } if (sum < rightSum) { sum = rightSum; } } return sum; } int main() { int len = 0, l = 0, r = 0; int array[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 }; //数组长度 len = sizeof(array) / sizeof(*array); //打印原始数组 cout << "The Array is: " << endl; PrintArray(array, 0, len - 1); //寻找最大子数组 cout << "The MaxSum is: " << endl; cout << MaxSubSum(array, 0, len - 1, l, r) << endl; ///打印最大子数组 cout << "The MaxSumArray is: " << endl; PrintArray(array, l, r); system("pause"); return 0; } /* The Array is: 13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7 The MaxSum is: 43 The MaxSumArray is: 18 20 -7 12 请按任意键继续. . . */