经典算法问题 - 最大连续子数列和

Posted cstdio1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了经典算法问题 - 最大连续子数列和相关的知识,希望对你有一定的参考价值。

维基百科:在计算机科学中,最大子数列问题的目标是在数列的一维方向找到一个连续的子数列,使该子数列的和最大。例如,对一个数列 −2, 1, −3, 4, −1, 2, 1, −5, 4,其连续子数列中和最大的是 4, −1, 2, 1, 其和为6。

时间复杂度:O(N^3)

最粗鲁的做法就是直接三重循环,起点i,终点j,k是从i到j

代码如下:

#include <bits/stdc++.h>

using namespace std;
                      
int main()

    int n;
    cin>>n;
    int a[n];
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    int ans=a[0];
     for(int i=0;i<n;i++)
         for(int j=0;j<n;j++)
             int s=0;
             for(int k=i;k<=j;k++)
              s+=a[k];     
             ans=max(ans,s);
         
     cout<<ans;
    return 0;

时间复杂度:O(N^2)

将上述代码稍微优化一下(空间换时间)

#include <bits/stdc++.h>

using namespace std;
                      
int main()

    int n;
    cin>>n;
    int a[n],sum[n];//sum[i]表示从a[0]+a[1]+.....+a[i]; 
                        //sum[j]表示从a[0]+a[1]+.....+a[i]+....+a[j];
    memset(sum,0,sizeof(sum));
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    sum[0]=a[0];
    for(int i=1;i<n;i++)
        sum[i]+=sum[i-1]+a[i];
    
    int ans=a[0];
     for(int i=1;i<n;i++)
         for(int j=i;j<n;j++)
             int s=sum[j]-sum[i-1];//sum[j]-sum[i-1]表示a[i]+....+a[j] 
            ans=max(ans,s); 
         ans=max(ans,sum[n-1]);//因为s是sum[j]-sum[i-1]出来的所以至少减去了一个sum[0],
                                 //所以还得比较一次全部相加的结果 
     cout<<ans;
    return 0;

时间复杂度:O(N)

 

Kadane算法[编辑]

 

Kadane算法扫描一次整个数列的所有数值,在每一个扫描点计算以该点数值为结束点的子数列的最大和(正数和)。该子数列由两部分组成:以前一个位置为结束点的最大子数列、该位置的数值。因为该算法用到了“最佳子结构”(以每个位置为终点的最大子数列都是基于其前一位置的最大子数列计算得出),该算法可看成动态规划的一个例子。

算法可用如下Python代码实现:

def max_subarray(A):
    max_ending_here = max_so_far = A[0]
    for x in A[1:]:
        max_ending_here = max(x, max_ending_here + x)
        max_so_far = max(max_so_far, max_ending_here)
    return max_so_far

常用的c++代码:

#include <bits/stdc++.h>

using namespace std;
                      
int main()

    int n;
    cin>>n;
    int a[n],dp[n];//dp[i]:截至到第i项的最大和 
    for(int i=0;i<n;i++)
        cin>>a[i];
        dp[0]=a[0];
    int ans=a[0]; 
    for(int i=1;i<n;i++)
        dp[i]=max(dp[i-1]+a[i],a[i]);//如果a[i]>dp[i-1]+a[i],
                                    //说明现在以a[i]作为新的起点累加的结果更大 
        ans=max(ans,dp[i]);            //注意最大的不一定是dp[n-1] 
    
    cout<<ans;
    return 0;

 

技术图片
#include <bits/stdc++.h>

using namespace std;
                      
int main()

    int n;
    cin>>n;
    int a[n]; 
    for(int i=0;i<n;i++)
        cin>>a[i];
        
    int ans=a[0]; 
    for(int i=1;i<n;i++)
        a[i]=max(a[i-1]+a[i],a[i]);
        ans=max(ans,a[i]); 
    
    cout<<ans;
    return 0;
不开辟dp数组

 

贪心:

#include <bits/stdc++.h>

using namespace std;
                      
int main()

    int n;
    cin>>n;
    int a[n]; 
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    int s=0,ans=a[0];    
    for(int i=0;i<n;i++)
    s+=a[i];
    ans=max(s,ans);
    if(s<0)
    s=0;    
    
    
    
    cout<<ans;
    return 0;

 

  

 

以上是关于经典算法问题 - 最大连续子数列和的主要内容,如果未能解决你的问题,请参考以下文章

经典算法——连续子数组最大和问题

最大连续子数列和

算法:管窥算法-最大连续子序列和

最大连续子数列和

经典算法——连续子数组的最大乘积

算法简单题,吾辈重拳出击 - 连续子数组的最大和