微信扫一扫打赏支持

算法与数据结构---4.2、最大子段和-枚举优化

算法与数据结构---4.2、最大子段和-枚举优化

一、总结

一句话总结:

对最大子段和的枚举优化,就是通过预处理来减少重复的计算
/*
枚举优化

可以把求和的那层循环去掉,我们可以对数据做预处理
用s[i]表示第一个数到第i个数这个序列的和

那么求s[i-j](第i个数到第j个数这个序列的和)的时候,
可以直接用s[j]-s[i]+a[i]即可
s[j]-s[i]表示的是i+1到j这个序列的和,所以需要加上a[i]

现在的时间复杂度:
O(n)+O(n^2)=O(n^2)

优化方法:
减少重复计算


*/
#include <iostream>
using namespace std;
int a[200005];
int s[200005]={0};
int main(){
    int n;
    cin>>n;
    int maxx=-0x7fffffff;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s[i]=s[i-1]+a[i];
    }
    //1、枚举每一段的起点和终点
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            //2、对每一段进行求和,在这些和里面选出最大的
            int sum=s[j]-s[i]+a[i];
            if(sum>maxx) maxx=sum;
        }
    }
    cout<<maxx<<endl;
    return 0;
}

 

 

 

二、最大子段和-枚举优化

博客对应课程的视频位置:4.2、最大子段和-枚举优化
https://www.fanrenyi.com/video/27/264

 

1、题目描述

最大子段和(最大连续子序列的和)

题目描述
给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。

输入格式
第一行是一个整数,表示序列的长度 n。
第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字 ai

输出格式
输出一行一个整数表示答案。

输入输出样例
输入
7
2 -4 3 -1 2 -4 3
输出
4

说明/提示
样例解释
选取 [3,5] 子段{3,−1,2}最大,其和为 4。

数据规模与约定
对于40%的数据,保证n<=2×10^3
对于100%的数据,保证1<=n<=2×10^5, -10^4<=a[i]<=10^4

题目提交位置:
P1115 最大子段和 - 洛谷
https://www.luogu.com.cn/problem/P1115

 

2、枚举解法

 1 /*
 2 枚举法
 3 
 4 分析:
 5 我们可以直接按照题目的要求来枚举就好了
 6 
 7 题目的要求是要 求a[1]-a[n]中连续非空的一段的和最大
 8 那么我们把每个连续的一段都枚举出来,然后来算出里面的和,找出最大值即可
 9 
10 所以在这个需求下:
11 我们需要枚举每一段的起点、每一段的终点
12 然后对这一段进行求和
13 
14 枚举变量:每一段的起点、终点
15 枚举范围:起点:1-n,终点:起点-n
16 枚举判断条件:
17 求和得到每一段的和,在这些和里面选出最大的
18 
19 时间复杂度:
20 O(n^3)
21 
22 算法思路:
23 1、枚举每一段的起点和终点
24 2、对每一段进行求和,在这些和里面选出最大的
25 
26 */
27 #include <iostream>
28 using namespace std;
29 int a[200005];
30 int main(){
31     int n;
32     cin>>n;
33     int maxx=-0x7fffffff;
34     for(int i=1;i<=n;i++){
35         cin>>a[i];
36     }
37     //1、枚举每一段的起点和终点
38     for(int i=1;i<=n;i++){
39         for(int j=i;j<=n;j++){
40             //2、对每一段进行求和,在这些和里面选出最大的
41             int sum=0;
42             for(int k=i;k<=j;k++){
43                 sum+=a[k];
44             }
45             if(sum>maxx) maxx=sum;
46         }
47     }
48     cout<<maxx<<endl;
49     return 0;
50 }

 

3、枚举优化

 1 /*
 2 枚举优化
 3 
 4 可以把求和的那层循环去掉,我们可以对数据做预处理
 5 用s[i]表示第一个数到第i个数这个序列的和
 6 
 7 那么求s[i-j](第i个数到第j个数这个序列的和)的时候,
 8 可以直接用s[j]-s[i]+a[i]即可
 9 s[j]-s[i]表示的是i+1到j这个序列的和,所以需要加上a[i]
10 
11 现在的时间复杂度:
12 O(n)+O(n^2)=O(n^2)
13 
14 优化方法:
15 减少重复计算
16 
17 
18 */
19 #include <iostream>
20 using namespace std;
21 int a[200005];
22 int s[200005]={0};
23 int main(){
24     int n;
25     cin>>n;
26     int maxx=-0x7fffffff;
27     for(int i=1;i<=n;i++){
28         cin>>a[i];
29         s[i]=s[i-1]+a[i];
30     }
31     //1、枚举每一段的起点和终点
32     for(int i=1;i<=n;i++){
33         for(int j=i;j<=n;j++){
34             //2、对每一段进行求和,在这些和里面选出最大的
35             int sum=s[j]-s[i]+a[i];
36             if(sum>maxx) maxx=sum;
37         }
38     }
39     cout<<maxx<<endl;
40     return 0;
41 }

 

 

 

 

 
posted @ 2020-06-02 09:14  范仁义  阅读(211)  评论(0编辑  收藏  举报