问题描述
给定一个数组arr[1…n],对于任意一堆数组下标为l,r(l<=r)的非空子数组,其和记为S(l,r)=
∑
i
=
l
r
a
r
r
[
i
]
\sum_{i=l}^rarr[i]
∑i=lrarr[i]
求出s(l,r)的最大值,记为Smax.
一、暴力枚举
1.问题分析
-
数组arr[1…n],其所有的下标l,r(l<=r)组合分为以下两种情况
- 当l=r时,一共n种组合
- 当l<r时,一共C(n,2)种组合
-
枚举n+C(n,2)种下标l,r组合,求出最大子数组之和
2.伪代码
3.代码实现
int sum(int *arr){
int smax = INT16_MIN;
for (int l = 0; l < 9;l++){
for (int r = l; r < 9;r++){
int s = 0;
for (int i = l; i < r;i++){
s = s + arr[i];
}
smax = max(smax, s);
}
}
return smax;
}
二、优化枚举
1.优化分析
上述枚举中,含有多次的重复操作,例如:S(3,8)需要将下标为3到下标为8的值相加,S(3,9)需要将下标为3到下标为9的值相加,其中3到8已经相加过了,可以重复利用之前已经计算的数据,以达到优化的目的。
2.伪代码
3.代码实现
int sum(int *arr){
int smax = INT16_MIN;
for (int l = 0; l < 9;l++){
int s = 0;
for (int r = l; r < 9;r++){
s = s + arr[r];
smax = max(smax, s);
}
}
return smax;
}
三、分治算法
1.算法流程
2.伪代码
3.代码实现
int CrossingSubArray(int* arr,int low,int mid ,int high){
int smax_left = INT16_MIN,smax_right=INT16_MIN;
int sum_left = 0,sum_right=0;
for (int i = mid; i >= low; i--){
sum_left = sum_left + arr[i];
smax_left = max(sum_left, smax_left);
}
for (int i = mid + 1; i <= high;i++){
sum_right = sum_right + arr[i];
smax_right = max(sum_right, smax_right);
}
return smax_left + smax_right;
}
int MaxSubArray(int *arr ,int low,int high){
if (low==high)
return arr[low];
int mid = (low + high) / 2;
int s1=MaxSubArray(arr, low, mid);
int s2=MaxSubArray(arr, mid + 1, high);
int s3=CrossingSubArray(arr,low,mid,high);
return max(max(s1, s2), s3);
}
四、总结
算法名称 | 时间复杂度 |
---|---|
暴力枚举 | O(n3) |
优化枚举 | O(n2) |
分而治之 | O(nlogn) |