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

维基百科:在计算机科学中,最大子数列问题的目标是在数列的一维方向找到一个连续的子数列,使该子数列的和最大。例如,对一个数列 −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;
}

 

  

 

转载于:https://www.cnblogs.com/cstdio1/p/11350983.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值