1.暴力思路:枚举子序列的起点和终点
暴力法的优化思路集中在子序列求和
/****
最初版想法,暴力枚举与暴力求和时间复杂度:O(n^3),
后来想到打表优化求和
时间复杂度降到O(n^2)
空间复杂度O(n)
****/
#include<stdio.h>
#include<iostream>
#define Maxsize 100005
using namespace std;
//s[t]:从0到t-1序列的和
long long s[Maxsize];
//暴力法求最大子序列和
long long solve(int* _array,int n){
long long sum = 0;
long long out = _array[0];
//枚举维度:(起点,终点)
//枚举起点
for(int i = 0 ;i<n ; i++){
//起点不为负数
if(_array[i]<0)
continue;
//枚举终点
for(int j = i ;j<n ;j++){
//终点不为负数
if(_array[j]<0)
continue;
//sum(j~i)-sum(i-1),子序列和
sum = s[j+1]-s[i];
if(sum>out)
out = sum;
}
}
return out;
}
int main(){
int n;
int flag = 0;
int _array[Maxsize];
cin>>n;
for(int i = 0 ;i<n ;i++){
cin>>_array[i];
//输入时打表
s[i+1]=_array[i]+s[i];
if(_array[i]>0)
flag = 1;
}
//全都为负数
if(!flag)
cout<<0<<endl;
else
cout<<solve(_array,n)<<endl;
return 0;
}
/***
参考别人代码,实际上枚举终点的过程中可以做累加,不需要额外空间记录子序列和
时间复杂度O(n^2)
空间复杂度O(1)
另:考虑到cin的速度较慢,改成scanf
**/
#include<stdio.h>
#define Maxsize 100005
int main(){
int n;
int out = 0;
int sum = 0;
int arr[Maxsize];
scanf("%d",&n);
for(int i = 0 ;i<n ;i++)
scanf("%d",&arr[i]);
for(int i = 0; i<n; i++){
if(arr[i]<0)
continue;
sum = 0;
for(int j = i; j<n; j++){
sum+=arr[j];
if(sum>out)
out = sum;
}
}
printf("%d\n", out);
return 0;
}
2.小学数学法:任何整数与负整数的和必然小于原数,为保证和最大,如果一个子序列的和为负数则应该丢弃这个序列
#include <stdio.h>
#define Maxsize 100005
int main(){
int n;
int out = 0;
int sum = 0;
int arr[Maxsize];
scanf("%d",&n);
for(int i = 0 ;i<n ;i++)
scanf("%d",&arr[i]);
for(int i = 0 ;i<n ;i++){
sum+=arr[i];
//如果子序列的和为负数,则丢弃这个子序列
if(sum<0)
sum = 0;
if(sum>out)
out = sum;
}
printf("%d\n", out);
return 0;
}