洛谷/Luogu P1115 最大子段和 题解
题目描述
给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度 n。
第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
7
2 -4 3 -1 2 -4 3
样例输出 #1
4
提示
样例 1 解释
选取 [3, 5] 子段 {3, -1, 2},其和为 4。
题解
1. 分治法
时间复杂度 O(n*log n),空间复杂度 O(n)
经过分析,发现最大子序列和可能在三处出现。
- 出现在输入数据的左半部分- 出现在输入数据的右半部分
- 跨越输入数据的中间元素,从而占据左右两半部分
前两种情况可以递归求解。第三种情况的最大和可以通过求出前半部分的最大和(包括前半部分的最后一个元素)以及后半部分的最大和(包括后半部分的第一个元素),再将两部分相加得到。
#include <stdio.h>
#include <stdlib.h>
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int tripleMax(const int a, const int b, const int c);
int MaxSubSum(const int *a, const int begin, const int end);
int main() {
int n, i;
scanf("%d", &n);
int *a = (int *)malloc(n * sizeof(int));
for (i = 0; i < n; i++)
scanf("%d", a + i);
printf("%d", MaxSubSum(a, 0, n - 1));
free(a);
return 0;
}
int tripleMax(const int a, const int b, const int c) {
if (a >= b && a >= c)
return a;
else if (b >= a && b >= c)
return b;
else
return c;
}
int MaxSubSum(const int *a, const int begin, const int end) {
int m = (begin + end) >> 1, i;
int leftBorderSum = a[m], rightBorderSum = a[m + 1];
int maxLeftBorderSum = a[m], maxRightBorderSum = a[m + 1];
if (begin == end)
return a[begin];
int maxLeftSum = MaxSubSum(a, begin, m);
int maxRightSum = MaxSubSum(a, m + 1, end);
for (i = m - 1; i >= begin; i--) {
leftBorderSum += a[i];
maxLeftBorderSum = MAX(leftBorderSum, maxLeftBorderSum);
}
for (i = m + 2; i <= end; i++) {
rightBorderSum += a[i];
maxRightBorderSum = MAX(rightBorderSum, maxRightBorderSum);
}
return tripleMax(maxLeftSum, maxRightSum,
maxLeftBorderSum + maxRightBorderSum);
}
2. 贪心法
时间复杂度 O(n),空间复杂度 O(1)
用 f(i) 代表以第 i 个数结尾的连续子数组的最大和,则有
f(i) = max(a[i], f(i- 1) + a[i])
#include <limits.h>
#include <stdio.h>
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int main() {
int n, item, sum = 0, maxSum = INT_MIN;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &item);
sum = MAX(sum + item, item);
maxSum = MAX(sum, maxSum);
}
printf("%d", maxSum);
return 0;
}
本文链接:
/archives/luogup1115
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
Integral's Blog!
喜欢就支持一下吧