zoukankan      html  css  js  c++  java
  • 题解 【洛谷P1115】最大子段和

    这是一道枚举经典题。

    本题有三种做法,各位需要根据每个题的数据范围来决定自己用哪种方法。

    本题解中统一设最大和为Max。

    方法一、 枚举子序列,从起点到终点求和。时间复杂度:O(n^3)

    我们可以枚举它的子序列,也就是枚举它的长度、起点和终点。我们不妨设长度为i,起点为j,终点为k,当前子序列的和为s。于是我们就有了下列核心代码:


        Max=a[1];//最大和初始化为第一个数
        for(i=1;i<=n;i++)//枚举长度
            for(j=i;j<=n;j++){//枚举起点
                s=0;//当前序列和初始化为0
                for(k=i;k<=j;k++)//枚举终点
                    s+=a[k];//计算和
                if(s>Max)Max=s;//比较
            }
        printf("%d",Max);//输出

    这种方法在时限1s的题目中只能通过n<=450的范围。

    但是本题的序列长度n<=200000。

    所以采用该方法超时。

    方法二、先求前缀和,再枚举。时间复杂度:O(n^2)

    我们可以先求出从第一个数到当前数的和,然后枚举起点和终点,计算每一个子序列的和。于是我们就有了下列核心代码:


        memset(s,0,sizeof(s));//初始化前缀和
        for(i=1;i<=n;i++)s[i]=s[i-1]+a[i];//计算前缀和
        Max=a[i];//初始化最大值为第一个数
        for(i=1;i<=n;i++)
            for(j=i;j<=n;j++)
                Max=max(Max,s[j]-s[i-1]);//枚举起点和终点。
                //注意是i-1!因为计算从第i个数开始的和需要减去前i-1个数的和
        printf("%d",Max);

    怎么有点像DP?

    这种方法在时限1s的题目中只能勉强通过n<=10000的范围。

    但是本题的序列长度n<=200000。

    所以采用该方法也超时。

    方法三、直接从头开始计算和,并每次记录最大和。时间复杂度:O(n)

    不妨设s为以第i个数结尾的最大和,并每次计算和。

    若当前和比最大值大,就更新最大值。

    若当前和比0小,就把和清0。

    核心代码:


        scanf("%d",&n);
        s=0;
        Max=-2e9;
        for(i=1;i<=n;i++){
            scanf("%d",&a);
            s+=a;
            if(s>Max)Max=s;
            if(s<0)s=0;
        }
        printf("%d",Max);

    这种方法在时限1s的题目中能勉强通过n<=100000000的范围。

    由于本题的序列长度n<=200000。

    所以可以采用这种方法。

    总结:一定要明白第三种方法的道理,并且能自己编写代码,这样水平才能有所提升。

  • 相关阅读:
    Redis简介 安装 注册服务
    Supervisor Linux守护进程
    .Net5 控制台 读取配置文件+依赖注入
    Linux Gdip
    Net Core封装 踩坑
    Apollo 公共Namespace使用json
    Visual Studio 2019修改项目名
    【面向对象】--静态类与非静态类的区别
    win10设置默认中英文符号【程序员标配】
    MySQL 数据库访问驱动-版本问题
  • 原文地址:https://www.cnblogs.com/xsl19/p/10414741.html
Copyright © 2011-2022 走看看