MOOC 数据结构 最大子列和问题

原题:最大子列和

问题描述

“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

思路

  1. 穷举法 : 设置子列的left和right,列举出所有子列的情况,分别计算每个子列的和,进行比较求出最大值。

    for(left=0;left<n;left++)
     for(right=left+1;right<n; right++)
     {
      current_sum=0;
       for(int i=left; i<right; i++)
         {
          current_sum+=sequence[i];
          if(current_sum>max_sum)
             max_sum=current_sum;
         }
    }
  2. 穷举法改进: 当left确定时,子列和随着right的后移在上一次的计算结果上进行运算,所以可以在每次的begin开始时将当前子列和归零。

    for(int left=0; left<n; i++)
    {
       int current_sum=0;
       for(int right=left; right<n; right++){
        current_sum+=sequence[right];
        if(current_sum>max_sum)
           max_sum=current_sum;
        }
     }
  3. 在线处理 : (本题不考虑和为负数的情况)当子列和小于0时,它对于最大子列和没有贡献(即该段子列肯定不在最大子列当中),可以将当前子列和归零,继续后面的寻找。

    for(int i=0; i<n; i++)
    {
     current_sum+=sequence[i];
     if(current_sum>max_sum)
       max_sum=current_sum;
     if(current_sum<0)//关键点
        current_sum=0;
    }

比较

方法复杂度
1O(n^3)
2O(n^2)
3O(n)

加强版

原题: 最大子列和2

问题分析

(1)考虑到全是负数和只有负数和0的情况:可以设置一个Max函数返回母序列的最大值。若最大值为0,则是只有负数和0(也可能全为0)的情况,最大子序列就是母序列中的第一个0;若最大值小于0,则是全是负数的情况,按照题意最大子列和设为0,并输出母序列的第一个值和最后一个值。

 if(max<=0)
  {
    //全为负数
    if(max<0){
      max_sum=0;
      begin=sequence[0];
      end=sequence[n-1];}
    int j=0;
    //负数和0
    if(max==0){
      while(sequence[j]!=0){
        j++;
      }
      max_sum=0;
      begin=sequence[j];
      end=sequence[j];
    }
  }

(2)解决输出最大子列的头和尾的问题: 可以在在线处理的方法上进行简单的修改即可。由之前说的在线处理方法可知,在子列和小于等于0的时候对于最大子列和是没有贡献的,所以我们可以在子列和小于0的时候记录下当前位置,则最大子列的开头位置就是该位置的后一个位置,结尾位置可以直接在记录最大子列和的时候同时记下。

for(int i=0; i<n; i++)
    {
     current_sum+=sequence[i];
     if(current_sum<=0){
        current_sum=0;
        p=i+1;
     }
     if(current_sum>max_sum)
     {
        max_sum=current_sum;
        end=sequence[i];
        begin=sequence[p];
     }
    }

完整程序实现

1

#include<iostream>
using namespace std;
const int K=100000;

int subsequence1(int sequence[],int n){
   int left,right;
   int current_sum=0;
   int max_sum=0;
   for(left=0;left<n;left++)
    for(right=left+1;right<n; right++)
    {
      current_sum=0;
      for(int i=left; i<right; i++)
         {
          current_sum+=sequence[i];
          if(current_sum>max_sum)
             max_sum=current_sum;
         }
    }
    return max_sum;
}


int subsequence2(int sequence[],int n){
    int max_sum=0;
    for(int i=0; i<n; i++){
        int current_sum=0;
      for(int j=i; j<n; j++){
        current_sum+=sequence[j];
        if(current_sum>max_sum)
         max_sum=current_sum;
      }
    }
    return max_sum;
}

int subsequence3(int sequence[],int n){
  int current_sum=0;
  int max_sum=0;
  for(int i=0; i<n; i++)
    {
     current_sum+=sequence[i];
     if(current_sum>max_sum)
       max_sum=current_sum;
     if(current_sum<0)
        current_sum=0;
    }
  return max_sum;
}

int main(){
  int sequence[K];
  int N;
  cin>>N;
  for(int i=0; i<N; i++)
    cin>>sequence[i];
  cout<<subsequence2(sequence,N)<<endl;
  return 0;
}

2加强版

#include<iostream>
using namespace std;
const int K=100000;

int Max(int sequence[],int n)//找出数组中的最大值
{
    int max=sequence[0];
    for(int i=0;i<n;i++)
     if(sequence[i]>max)
        max=sequence[i];
    return max;
}

int subsequence(int sequence[],int n){
  int current_sum=0;
  int max_sum=0;
  int begin;
  int end;
  int p=0;
  int max=Max(sequence,n);
  if(max<=0)
  {
    //全为负数
    if(max<0){
      max_sum=0;
      begin=sequence[0];
      end=sequence[n-1];}
    int j=0;
    //负数和0
    if(max==0){
      while(sequence[j]!=0){
        j++;
      }
      max_sum=0;
      begin=sequence[j];
      end=sequence[j];
    }
  }
  for(int i=0; i<n; i++)
    {
     current_sum+=sequence[i];
     if(current_sum<0){
        current_sum=0;
        p=i+1;
     }
     if(current_sum>max_sum)
     {
        max_sum=current_sum;
        end=sequence[i];
        begin=sequence[p];
     }
    }
  cout<<max_sum<<" "<<begin<<" "<<end;
}

int main(){
  int sequence[K];
  int N;
  cin>>N;
  for(int i=0; i<N; i++)
    cin>>sequence[i];
  subsequence(sequence,N);
  return 0;
}

鸡汤

第一次写博客,希望可以坚持下去!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值