• 最大子列和


    题目描述

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

    输入格式

    第一行是一个整数,表示序列的长度 n。
    第二行有 n 个整数,第 i个整数表示序列的第 i个数字 (a_i)

    输出格式

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

    输入输出样例

    输入

    7
    2 -4 3 -1 2 -4 3

    输出

    4

    数据范围

    对于 40% 的数据,保证 n (leq) 2 ( imes) (10^3)
    对于 100% 的数据,保证 n (leq) 2 ( imes) (10^5),-(10^4) (leq) (a_i) (leq) (10^4)

    思路1(暴力求解):

    计算出每个子序列的和再选出其中最大的那一个。(注意:根据这道题目的数据范围来说,这个思路会TLE)

    #include<iostream>
    #include<vector>
    using namespace std;
    typedef long long int ll;
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n;
        vector<int> a(n+5),s(n+5);
        for(int i=1;i<=n;i++)
        {
             cin>>a[i];
             s[i]=s[i-1]+a[i];//前缀和处理一下
        }
        ll maxSum=a[1];
        for(int i=1;i<=n;i++)//i代表子序列的左端点
        {
            for(int j=i;j<=n;j++)//j代表子序列的右端点
               if(s[j]-s[i-1]>maxSum)//s[j]-s[i-1]=a[i]+a[i+1]+...+a[j]
               maxSum=s[j]-s[i-1];
        }
        cout<<maxSum<<endl;
        return 0;
    }
    

    思路2(分治思想):

    将一个序列分成两段,分别求两个子序列的最大子序列和,再求出越过序列分界点的最大子序列和,那么序列的最大子序列和一定是三个值中的最大值。
    1)如何求两个子序列的最大子序列和?
    答:将这两个子序列分别再分成两段,当子序列中只有一个数字的时候最大子列和就是这个数字,再递归返回就可以了。
    2)如何求出越过序列分界点的最大子序列和?
    答:从分界点左端扫描,维护出一个leftMax;同理,右端维护出一个rightMax。leftMax+分界点处的值+rightMax即为所求。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long int ll;
    int a[200005];
    ll cal(int l,int r)
    {
        if(l>=r)
        return a[l];
        int mid=(l+r)>>1;
        ll leftMax=0,rightMax=0,thisSum=0;
        for(int i=mid-1;i>=l;i--)
        {
            thisSum+=a[i];
            if(thisSum>leftMax)
            leftMax=thisSum;
        }
        thisSum=0;
        for(int i=mid+1;i<=r;i++)
        {
            thisSum+=a[i];
            if(thisSum>rightMax)
            rightMax=thisSum;
        }
        return max(max(cal(l,mid),cal(mid+1,r)),leftMax+a[mid]+rightMax);//求出cal(l,mid),cal(mid+1,r),leftMax+a[mid]+rightMax三者之间的最大值
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
             cin>>a[i];
        }
        cout<<cal(1,n)<<endl;
        return 0;
    }
    

    思路3(动态规划):

    根据题意我们可以得出以下结论:
    1)第一个数字为有效序列。
    2)如果一个数加上上一个有效序列得到的结果比这个数大(即前面的子列和>0),那么该数也属于这个有效序列。
    3)如果一个数加上上一个有效序列得到的结果比这个数小(即前面的子列和<0),那么这个数单独成为一个新的有效序列,我们需要将前面的子列和抛弃,即重新归0。
    综上,我们可以得出以下代码:

    #include<iostream>
    #include<vector>
    #include<algorithm>
    using namespace std;
    typedef long long int ll;
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,x;
        ll thisSum=0,maxSum=-10005;
        cin>>n;
        while(n--)
        {
            cin>>x;
            thisSum+=x;//向右累加
            maxSum=max(maxSum,thisSum);//发现更大和则立即更新当前结果
            if(thisSum<0)//如果当前子列和为负,
            thisSum=0;//则不可能使后面的子列和更大,抛弃它
            
        }
        cout<<maxSum<<endl;
        return 0;
    }
    
  • 相关阅读:
    用DeBug的方式,带你掌握HBase文件在Snapshot的各种变化
    业务随行:用户的网络访问策略还能这么玩
    清明节特辑 |记忆存储、声音还原、性格模仿……AI可以让人类永生吗?
    答题拿奖两不误:华为云知乎金牌答题官,就是你!
    一文掌握GaussDB(DWS) SQL进阶技能:全文检索
    LiteOS内核源码分析:任务栈信息
    INTERSPEECH2020 语音情感分析论文之我见
    统一元数据,数据湖Catalog让大数据存算分离不再是问题
    云图说|将源端MongoDB业务搬迁至华为云DDS的几种方式
    跟我学丨如何用鲲鹏服务器搭建Hadoop全分布式集群
  • 原文地址:https://www.cnblogs.com/Acapplella/p/13468304.html
Copyright © 2020-2023  润新知