分析:
一: 分治法:把问题分解成若干个简单易解的小问题,最后再把小问题归并起来,找到我们原来要解决问题的解
二: 扫描法
此种方法是这类问题的最优解法。时间复杂度是 O(n)。 上面的分治算法时间复杂度是 O(nlogn)
算法实现:
int FindMaxinumSubarray1(int * A, int low, int high)
{
int Sum = 0;
int temp = 0;
for (int i = low; i <= high; i++)
{
temp += A[i];
if (temp > Sum)
Sum = temp;
if (temp < 0)
temp = 0;
}
问题就是该怎么来理解这个分段:
例如: 一开始,我们另 Sum为 负无穷,这样我们可以保证至少有一个分段的总和是大于 Sum ,并会把分段中的结果temp赋值给Sum。
如 下标i=0 时, temp += A[0] , 即 temp = 2。
ps: temp 每一次更新值,都要做两次判断
1: 判断 是否要更新 Sum 的值,即子数组最大和的值
2: 判断 是否要更新 temp的值。 每当 temp 的值被累计到 负数 时, 就更新temp的值,令 temp = 0
temp 大于 此时的 Sum , 即 Sum 被更新, Sum = temp, Sum = 2 (当前最大子数组和)
temp 大于0, 继续累加
i = 1 , temp += A[1] , 即 temp = 6
temp 大于 Sum , 更新 Sum, Sum = temp , Sum = 6 (当前最大子数组和)
temp 大于 0 , temp 继续累加
.........
当 i = 5 时, A[i] = -4
此时 temp = -1 小于 0 , 即 temp 要被更新 , temp = 0
........
ps : 其他解决这类问题的算法还有 动态规划法和暴力破解法。
下面是C语言代码实现
#include
#include
#include
int* FindMaxCrossingSubarray(int* A, int low, int mid, int high); //寻找跨越中点的最大子数组
int* FindMaximunSubarray(int*A , int low, int high); // 寻找没有跨越中点的最大子数组
void Print(int *A,int length); //打印结果
int FindMaxinumSubarray1(int*A, int low, int high);
int main()
{
int A[] = {2,4,-1,-5,3,-4,2,-6,4,1,2,2,4,-2,2};
int *p = A;
Print(p,15);
p = FindMaximunSubarray(A,0,14);
for (int i = 0; i < 3; i++)
{
printf("%d ",*(p+i));
}
printf("-----------------------------\n");
printf("%d ",FindMaxinumSubarray1(A,0,14));
system("pause");
return 0;
}
int * FindMaxCrossingSubarray(int * A, int low, int mid, int high)
{
int LeftSum = INT_MIN;
int Sum = 0;
int MaxLeft = mid;
for (int i = mid; i >= low; i--)
{
Sum = Sum + *(A+i);
if (Sum > LeftSum)
{
LeftSum = Sum;
MaxLeft = i;
}
}
int RightSum = INT_MIN;
int MaxRight = mid+1;
Sum = 0;
for (int j = mid + 1; j <= high; j++)
{
Sum = Sum + *(A+j);
if (Sum > RightSum)
{
RightSum = Sum;
MaxRight = j;
}
}
int *re = (int*)malloc(sizeof(int)*3);
*re = MaxLeft;
*(re + 1) = MaxRight;
*(re + 2) = LeftSum + RightSum;
return re;
}
int * FindMaximunSubarray(int *A, int low, int high)
{
if (low == high)
{
int *re = (int*)malloc(sizeof(int) * 3);
*re = low;
*(re + 1) = high;
*(re + 2) = A[low];
return re;
}
else
{
int mid = (low + high) / 2;
int *Arr1 = FindMaximunSubarray(A, low, mid);
int *Arr2 = FindMaximunSubarray(A,mid+1,high);
int *Arr3 = FindMaxCrossingSubarray(A, low, mid, high);
if (*(Arr1 + 2) > *(Arr2 + 2) && *(Arr1 + 2) > *(Arr3 + 2))
return Arr1;
else if (*(Arr2 + 2) > *(Arr1 + 2) && *(Arr2 + 2) > *(Arr3 + 2))
return Arr2;
else
return Arr3;
}
}
void Print(int * A, int length)
{
int *q = A + length ;
for (int* p = A; p < q; p++)
{
printf("%d ",*p);
}
/*for (int i = 0; i < length; i++)
{
printf("%d ",*(A+i));
}*/
printf("\n");
}
int FindMaxinumSubarray1(int * A, int low, int high)
{
int Sum = 0;
int temp = 0;
for (int i = low; i <= high; i++)
{
temp += A[i];
if (temp > Sum)
Sum = temp;
if (temp < 0)
temp = 0;
}
return Sum;
}