求最大子数组:
一给定好的数组,在不改变起排列顺序的情况下,求非空的求和最大的子数组。
思路:把原数组分成两半,分别求两半的最大子数组,再求这两半合并后从中间往两边的最大子数组。然后把这三部分比较,得到整个的最大子数组。
即:1只取左边最大
2只取右边最大
3两边至少都包含一个的最大
(前提条件是得到的子数组是连续的,不能间段)
例子:先分,如图
再治:
上代码:
#include<iostream>
using namespace std;
#include<limits.h>
int max(int a, int b, int c)
{
return a > (b > c ? b : c)?a:(b > c ? b : c);
}
int crossing_sub_array(int a[],int left,int mid,int right)
{
int S_left = INT_FAST16_MIN; // 把由中向左求和初始值定义为负无穷
int sum = 0; // 临时储存求和变量
// 跨区域求和是求left和right这个大区间内由中往两边的最大值,而不是全求和(全求和不一定是最大)
// 求由中往左的最大
for (int i = mid; i >= left; --i)
{
sum += a[i]; // 直接在前面的基础上加,优化算法
if (S_left < sum)
S_left = sum;
}
int S_right = INT_FAST16_MIN;
sum = 0;
// 求由中往右的最大
for (int i = mid + 1; i <= right; ++i)
{
sum += a[i];
if (S_right < sum)
S_right = sum;
}
// 即使S_right和S_left一正一负抵消变小也没关系,因为主递归函数已经把只取右边最大部分和只取左边最大部分都求好了,最后比较三个S取最大的就行
int S3 = S_right + S_left;
return S3;
}
int max_sub_array(int a[], int left, int right)
{
if (left == right)
return a[left]; // 如果只有一个元素,就是递归的出口
int mid = (left + right) / 2;
int S1 = max_sub_array(a, left, mid); // 求左半部分的最大和
int S2 = max_sub_array(a, mid + 1, right); // 求右半部分的最大和
int S3 = crossing_sub_array(a, left, mid, right); // 跨中间区域求最大和(中间两边都至少包含一个的情况)
int S_max = max(S1, S2,S3); // 最大和是这三个中最大的
return S_max;
}
int main()
{
int array[7] = { 1,-2,4,5,-6,8,3, };
double S=max_sub_array(array, 0, 6);
cout << S << endl;
return 0;
}
深度logn,每层遍历了n次,则时间复杂度O(nlogn)