问题描述
给定由n个整数(包含负整数)组成的序列a1,a2,…,an,求该序列子段和的最大值。规定当所有整数均为负值时定义其最大子段和为0
穷举法
最简单的方法就是穷举法,用一个变量指示求和的开始位置,一个变量指示结束位置,再一个变量指示当前要加和的位置,每一个开始位置对应n-i个结束位置,遍历一遍就能得到最大值
int maxSubArray(int a[], int n) {
int maxsum = 0;
for (int i = 0; i < n; i++) {
//开始位置
for (int j = i; j < n; j++) {
//结束位置
int nowsum = 0;
for (int k = i; k <= j; k++) {
nowsum += a[k];
if (nowsum > maxsum)
maxsum = nowsum;
}
}
}
return maxsum;
}
算法有三重循环,时间复杂性为O(n^3)
穷举法优化
当字段的开始下标确定后,要计算[i:j]的字段和可以利用上一次计算的[i:j-1]的字段和,加上a[j]就可以了
int maxSubArray2(int a[], int n) {
int maxsum = 0;
for (int i = 0; i < n; i++) {
//开始位置
int nowsum = 0;
for (int j = i; j < n; j++) {
//结束位置
nowsum += a[j];
if (nowsum > maxsum)
maxsum = nowsum;
}
}
return maxsum;
}
改进后的时间复杂度为O(n^2)
分治法
该问题也可以用分治法解决
分治策略思想如下:
将所给序列a[1:n]分成长度相同的两端a[1:n/2]、a[n/2 +1:n],分别求出这两段的最大子段和,则整体序列a[1:n]的最大子段和有以下三种情况
- a[1:n]的最大子段和与a[1:n/2]的最大子段和相同
- a[1:n]的最大子段和与a[n/2 +1:n]的最大子段和相同
- a[1:n]的最大子段和是a[1:n/2]最后一段加a[n/2 +1:n]最开始一段的和
前两种情况可以递归求得。对于第三种情况,可以发现,a[n/2]和a[n/2 +1]都在最大子段里,我们可以从a[n/2]向左、从a[n/2 +1]向右分别计算两个最大字段和s1和s2,s1+s2就是最大子段和
递归方程
MaxSum(low,high)={ max(0, arr[low])if low=highmax{ MaxSum(low,mid)MaxSum(mid+1,high)CrossSum(low,mid,high)otherwise \text{MaxSum}(low, high) = \begin{cases} \displaystyle \max\left(0,\, \text{arr}[low]\right) & \text{if } low = high \\ \displaystyle \max \begin{cases} \text{MaxSum}(low, mid) \\ \text{MaxSum}(mid+1, high) \\ \text{CrossSum}(low, mid, high) \end{cases} & \text{otherwise} \end{cases} MaxSum(low,high)=⎩ ⎨ ⎧max(0,arr[low])max⎩ ⎨

最低0.47元/天 解锁文章
3万+

被折叠的 条评论
为什么被折叠?



