数据结构与算法——最大字段和

1、题目描述

求一个序列的最大子段和即最大连续子序列之和

2、枚举法

枚举变量:每一段的起点和终点
枚举范围:起点:1- n,终点:起点-n;
判断条件:找最大值即可
复杂度:O(NNN)

#include<iostream>
using nampespace std;
int a[20005];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];}
     int maxx=-0x7ffffffffor(int i=1;i<=n;i++)
     {
         for(int j=1;j<=n;j++)
         {
              int sum=0;
              for(int k=i;k<=j;k++)
              {
                   sum+=a[k];}
              if(sum>maxx)
                 maxx=sum;
              }


        }
     }
     cout<<maxx<<endl;             
     return 0;
     }

3、优化(减少重复计算)

序列从i 到 j 的一段和可以表示为从头到 j 的和减去从 从头到 i 段的和,最后再加上 a[i];
s[i-j]=s[j]-s[i]+a[i]
复杂度:O(N*N)

#include<iostream>
using nampespace std;
int a[20005];
int s[20005]={0}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=s[i-1]+a[i];
    }
     int maxx=-0x7ffffffffor(int i=1;i<=n;i++)
     {
         for(int j=1;j<=n;j++)
         {
              int sum=0;
              sum+=s[j}-s[i]+a[i];
              if(sum>maxx)
                 maxx=sum;
              }


        }
     }
     cout<<maxx<<endl;             
     return 0;
     }

4、分治解法(二分)

假设序列对应区间[l,r],其之间为mid,则最大子序列 [i,j] 有以下三种情况:
1、l<=i<=j<=mid;
2、i<=mid<=j<=r;
3、mid<=i<=j<=r;

分别取出这三种情况的值,再取他们的最大值;
复杂度:O(n)
首先,求区间[i … mid]最大值和区间[mid … j]最大值,也就是求以mid为头的序列最大值和以mid为尾。
首先以mid为头的序列最大值:

int maxx2=-0x7fffffff;
int sum2=0;
for( int k=mid;k<=j;k++)
{
       sum2+=a[k];
       maxx2=max(sum2,maxx2)
 }

以mid为尾:

int maxx1=-0x7fffffff;
int sum2=0;
for( int k=mid;k>=i;k--)
{
       sum1+=a[k];
       maxx2=max(sum1,maxx1)
 }

递归的终止条件:1、递归的区间为解;2、递归的区间只有一个元素

#include<iostream>
using namespace std;
int a[20005];
int find(int l,int r){
   if(l==r)  return a[l];
   int mid =(l+r)/2;
   //以mid为头的序列最大值:
   int maxx2=-0x7fffffff;
   int sum2=0;
   for( int k=mid;k<=r;k++)
{
       sum2+=a[k];
       maxx2=max(sum2,maxx2)
 }

//以mid为尾:
   int maxx1=-0x7fffffffint sum2=0;
   for( int k=mid;k>=l;k--)
{
       sum1+=a[k];
       maxx2=max(sum1,maxx1)
 }
   return max(max(find(l,mid),find(mid+1,r)),maxx1+maxx2-a[mid]);
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{ 
    cin>>a[i];
}
cout<<find(1,n)<<endle;
return 0;
5、贪心解法

若a[i-1]序列>0,则 s[i]+a[i-1]序列>a[i];
反之,若a[i-1]<0; 则不需要加上i-1前面的序列
假设必须选择a[i], 贪心过程的最优解就是以a[i]为结尾的子序列和s[i]最大的局部最优解.

#include<iostream>
using namespace std;
int a[20005];
int main()
{
  int n;
  cin>>n;
  for(int i=1; i<=n;i++)
     cin>>a[i];
  int sum=a[1];
  int maxx=a[1];
  for(int i=2;i<=n;i++)
  {
      if(sum<0) sum=0
      sum +=a[i];
      maxx=max(sum,maxx)
   }
   cout<<maxx<<endle;
   return 0;
  
  
6、动态规划

假设f[i]表示以第 i 个元素结尾的最大子序列的最大值,则:
f[i]=max(f[i-1]+a[i],a[i])
初始状态: f[1]=a[1]

#include<iostream>
using namsespace std;
int a[20005];
int f[20005];
int main()
{
  int n;
  cin>>n;
  for(int i=1; i<=n;i++)
  cin>>a[i];
  f[1]=a[1];
  int maxx=f[1];
  for(int i=2;i<=n;i++)
  {
     f[i]=max(f[i-1]+a[i],a[i]);
      maxx=max(f[i],maxx)
  }
  cout<<maxx<<endle;
  return 0;
       
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值