最大连续子序列和
给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大
输入
5
1 2 -5 11 3
输出
14
分析:设sum为连续子序列和,先从1开始,加2,再加-5,当加到-5时,sum=-2 < 0, 此时如果再加上11的话,sum=9, 我们发现-2明显拖了后腿,如果没有-2(前面序列舍去),只取第四个数据的话, sum=11会是更好的选择。
由此可以得到一个结论,当sum < 0时,可以直接舍去前面的值,把sum重新赋值为0,这样效率就是o(n)
#include <stdio.h>
#include <cstring>
int main() {
int n;
int sum = 0, t = 0, x;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
t += x;
if (t < 0) t = 0;
if (sum < t) sum = t;
}
printf("%d\n", sum);
return 0;
}
还有如果全部是负数的情况要怎么办呢?上面的代码是求不出答案的
最后改进代码就是
#include <stdio.h>
#include <cstring>
int main() {
long long n, x, sum;
scanf("%lld", &n);
scanf("%lld", &x);
sum = x;
long long t = x; // 用来累加
for (int i = 2; i <= n; i++) {
scanf("%lld", &x);
t += x;
if (sum < t) sum = t;
if (t < 0) {
if (x > 0) t = x; 舍去前面的之后,下一个开始的数肯定要是整数,不可能选一个负数开头
else t = 0;
}
}
printf("%lld\n", sum);
return 0;
}
// -2 1 -3 4 -1 2 1 -5 4 这个例子的答案是6, 4,-1,2,1
如果要输出序列的首尾位置呢?
这有个例题:https://blog.csdn.net/sincerit/article/details/83041762
最大连续子序列积
找出一个序列中乘积最大的连续子序列(至少包含一个数)并输出最大值。
输入
输入一个n,代表数的个数,以下n个数字中间以空格隔开
5
-5 3 9 10 -5
输出
6750
解决了最大连续子序列和的问题,最大连续子序列积问题要怎么办呢,肯定不是像最大连续子序列和一样去解决
这里要注意,由于存在负数,我们不能简单保存一个当前的最大值,还应保存一个最小值,因为有可能一个最小值再乘一个负数,得到一个最大值
思路:令f[n]表示[0,n]区间内,以n结尾的最大积,令g[n]表示[0,n]区间内,以n结尾的最小积,num为原序列则:
f[n] = max{f[n-1]*num[n], num[n], g[n-1]*num[n]}
g[n] = min{f[n-1]*num[n], num[n], g[n-1]*num[n]}
如下代码
#include <stdio.h>
#include <cstring>
long long max(long long a, long long b) {
return a>b?a:b;
}
long long min(long long a, long long b) {
return a>b?b:a;
}
long long num[100];
long long f[100];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%lld", &num[i]);
long long sum = num[0]; // 只有一个数的时候
long long tempmx = num[0], tempmi = num[0]; // 存放到当前位置是的最大最小的乘积 f[n], g[n]
for (int i = 1; i < n; i++) {
int fmx = tempmx; // f[n-1]
int fmi = tempmi; // g[n-1]
tempmx = max(num[i], max(num[i]*fmx, num[i]*fmi)); // 当前最大乘积 = max(当前数, max(当前数*之前的乘积最大,当前数*之前的乘积最小)) f[n] = max{f[n-1]*num[n], num[n], g[n-1]*num[n]}
tempmi = min(num[i], min(num[i]*fmx, num[i]*fmi)); // 再维护到当前的最小值
sum = max(tempmx, sum);
}
printf("%lld", sum);
return 0;
}