又是一个能让人眼前一亮的题,解的时候qiuqiu带感
一串整数a[1]…a[n],求子序列最大和,让算法复杂度最理想
plan A
不难想出
按照题目要求推
需要三次循环,复杂度为O(n^3),显然不是最优解
光荣下岗
#include<bits/stdc++.h>
using namespace std;
int main() {
int a[107],n;
scanf("%d",&n);
for(int i=1; i<=n; i++)//输入数组
scanf("%d",&a[i]);
int maxn=a[1];
for(int i=1; i<=n; i++) {//第一层循环
for(int j=i,sum=0; j<=n; j++) {//第二层循环
for(int k=i; k<=j; k++)//第三层循环
sum+=a[k];
if(sum>maxn) maxn=sum; } }
printf("%d",maxn);
return 0; }
plan B
智慧结晶plan B应运而生
可以三层循环降二层循环降一次循环
换个角度考虑问题,选择角度相对
加改为前缀和,乘改为除,开方改为平方,最大改为最小
降循环次数,需要多写一个一维循环
#include<bits/stdc++.h>
using namespace std;
int main() {
int a[107],s[107],n;
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int maxn=a[1];
s[1]=a[1];
for(int i=2; i<=n; i++)
s[i]=a[i]+s[i-1];//进行化简
for(int i=1; i<=n; i++)//第一层循环
for(int j=1; j<=n; j++)//第二层循环
if(s[j]-s[i-1]>maxn)
maxn=s[j]-s[i-1];
printf("%d",maxn);
return 0; }
时间复杂度是O(n^2),有所改进
plan A对于每一个i 通过每一个j 找到一个最大值(需要k 的参与),将这些最大值进行比较
plan B则通过一次循环简化掉k ,把求最大值的过程简单化了
将重复多次的加和运算变为一次性计算过的循环计算
把不同的计算变为一致的计算
plan C
对于每一个i 通过每一个j 的方法并不绝对简便
plan B省略了k,那能否省略j
奥夫考斯
#include<bits/stdc++.h>
using namespace std;
int main() {
int a[107],s[107],n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
int maxn=a[1],minn=a[1];
s[1]=a[1];
for(int i=2; i<=n; i++)
s[i]=a[i]+s[i-1];//进行化简
for(int i=1; i<=n; i++) {
if(s[i]<minn) minn=s[i];//确保i(min)在前,i(max)在后
if(s[i]-minn>maxn) maxn=s[i]-minn; }
printf("%d",maxn); }
改循环为变量交换
理解简单
与plan B相似,时间复杂度O(n)
plan D
是我最先的思路
把每一项与前一项相加,得到新的数组
再按照递归的思路,重复操作
当化简到最简数组时,就可通过每一项的数值求出最大值
但实施起来显然没有plan C简便
一来递归的出口不易找到;二来没有在大的全局的考量,导致解法复杂
顺便吐槽一下拖延症晚期的神通
2021.12.04