zoukankan      html  css  js  c++  java
  • 算法设计与分析——最大子段和(分治)

    一、问题描述

    Description

    给定有n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。

    Input

    第一行有一个正整数n(n<1000),后面跟n个整数,绝对值都小于10000。直到文件结束。

    Output

    输出它的最大子段和。

    Sample Input

    6 -2 11 -4 13 -5 -2
    

    Sample Output

    20

    解决该问题有很多方法可以通过暴力、动态规划和分治,这里使用分治的方法来解决该题目。

    二、分治策略

    用分治法求解这个问题 。

    在数组的 center = (right-left)/2+left 位置处分开。形成两个子数组。

    那么,最大子段和 可能出现在三个位置:

              a.可能出现在 左 子数组 

              b. 可能出现在 右子数组 

              c.可能出现在 过center的 中间某部分 元素 组成的子数组。

    下面考虑 三种情况的计算方法:

    第一种情况: 计算 left 到 center 的最大和,记作 leftSum

    第二种情况: 计算从 center+1 到 right的最大和,记作 rightSum

    第三种情况: 跨边界的和。 以center为中心分别向两边计算和。

          a.从 center出发,每次向左边扩张一步,并且记录当前的值S1,如果当前的和比上次的和大,就更新S1,一直向左扩张到位置 Left。 

          b.从 center+1出发,每次扩张一步,计算当前的和 为S2,如果当前的值比上次的和 大,那么,就更新S2的值,一直向右扩张到位置Right。

          c.计算过center的连续值的和,S1+S2的值 Sum。 这个就是跨边界的和。

    上面三种情况考虑计算完成后,最后一步就是,比较三个值中的最大值,取最大值就可以了。

    时间复杂度

    我们在(left+right)/2处,把大问题分成了两个部分的小问题。

    T(N)1=2T(N) 

    T(N)2=N

    在跨边界求和的时候,我们需要计算 从center出发的到 left方向的最大和,每次增加一个元素,通过比较,得到最大的和,时间复杂度为O(N),同样, 从center+1 出发的到 right 方向的最大和,每次增加一个元素,通过比较,得到最大的和,时间复杂度 为 O(N) ,所以,时间复杂度为  O(N)。

    伪代码

    Java源码

    import java.util.*;
    public class Main
    {
        public static int []a =new int[1010];
        public static int maxsum(int l,int r){
            if(l==r){
                return a[l];
            }
            int mid = (l+r)/2;
            int lsum = maxsum(l,mid);//左区间
            int rsum = maxsum(mid+1,r);//右区间
            int sum1=0,sum2=0;
            int lefts=0,rights=0;
            for(int i=mid;i>=l;i--){
                lefts+=a[i];
                if(lefts>sum1){
                    sum1=lefts;
                }
            }
            for(int i=mid+1;i<=r;i++){
                rights+=a[i];
                if(rights>sum2){
                    sum2=rights;
                }
            }
            int msum=sum1+sum2;
            return Math.max(Math.max(lsum,rsum),msum);
        }
        
        public static void main(String[] args){
            int n;
            int ans;
            Scanner in=new Scanner(System.in);
            while(in.hasNext()){
                n=in.nextInt();
                for(int i=1;i<=n;i++){
                    a[i]=in.nextInt();
                }
                ans = maxsum(0,n);
                if(ans<0){
                    ans=0;
                }
                System.out.println(ans);
            }
        }
    }

     C++源码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int a[110];
    int maxsum(int l,int r)
    {
        if(l==r)
        {
            return a[l];
        }
        int mid = (l+r)/2;
        int lsum = maxsum(l,mid);  //左区间
        int rsum = maxsum(mid+1,r);//右区间
        int sum1=0,sum2=0;
        int lefts=0,rights=0;      //跨界求和
        for(int i=mid; i>=l; i--)
        {
            lefts+=a[i];
            if(lefts>sum1)
            {
                sum1=lefts;
            }
        }
        for(int i=mid+1; i<=r; i++)
        {
            rights+=a[i];
            if(rights>sum2)
            {
                sum2=rights;
            }
        }
        int msum=sum1+sum2;
        return max(msum,max(lsum,rsum)); //三者中的最大值
    }
    
    int main()
    {
        int n;
        int ans;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1; i<=n; i++)
            {
               scanf("%d",&a[i]);
            }
            ans = maxsum(0,n);
            if(ans<0)
            {
                ans=0;
            }
           printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    鼠标滑过,解决ul下 li下a的背景与父级Li不同宽的问题
    php函数
    常用函数之数组函数
    php流程控制
    php运算符
    php常量
    php变量的数据类型
    PHP是什么
    css3新增属性
    html5的常用标签
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/11535615.html
Copyright © 2011-2022 走看看