关于求最大子段和的几种算法

一、比较朴素的算法

算法思想:我们确定每个子段和开始的位置,分别为第一个,第二个,第三个......第N个,然后计算从这个位置开始到这个位置之后的每个位置的子段和,更新记录最大的子段和。

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

算法实现(Java):

package com.Third;

import java.util.*;
public class Main3{
    public static int maxSum2(int a[]){
        int nowSum=0;//用于记录从指定位置到当前位置累加的值
        int maxSum=0;//用于记录当前最大的子段和
        for(int i=0;i<a.length;i++){
            nowSum=0;
            for(int j=i;j<a.length;j++){
                nowSum=nowSum+a[j];
                if(nowSum>maxSum){//更新最大子段和
                    maxSum=nowSum;
                }
            }
        }

        return maxSum;
    }
    public static void main(String[] args) {
        int a[]={4,-3,5,-2,-1,2,6,-2};
        System.out.println(maxSum2(a));
    }
}

二、分治法(递归)

算法思想:

通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下:
1.最大子段和出现在左端
2.最大子段和出现在右端
3.最大子段和横跨在左右段  通过比较大小得到最大子段和

时间复杂度:O(nlogn)

算法实现(Java):

package com.Third;
/*
 * 通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下:
 * 1.最大子段和出现在左端
 * 2.最大子段和出现在右端
 * 3.最大子段和横跨在左右段
 */
public class Main {
    public static int maxSumRec(int []a,int start,int end){
        if(start==end){//这里是递归的函数出口
            if(a[start]>0){
                return a[start];
            }else{
                return 0;
            }
        }
        int maxLeftSumRec=maxSumRec(a,start,(start+end)/2);//计算左半边的最大字段和
        int maxRightSumRec=maxSumRec(a,((start+end)/2)+1,end);//计算右半边最大子段和
        //计算最大子段和在中间的情况
        int leftMaxMark=0;
        int leftSum=0;
        for(int i=(start+end)/2;i>=0;i--){
            leftSum=leftSum+a[i];
            if(leftSum>leftMaxMark){
                leftMaxMark=leftSum;
            }
        }
        int rightMaxMark=0;
        int rightSum=0;
        for(int i=((start+end)/2)+1;i<=end;i++){
            rightSum=rightSum+a[i];
            if(rightSum>rightMaxMark){
                rightMaxMark=rightSum;
            }
        }
        int maxMidSumRec=leftMaxMark+rightMaxMark;
        //比较三种情况那种情况是最大的子段和
        int maxSum=maxLeftSumRec;
        if(maxSum<maxRightSumRec){
            maxSum=maxRightSumRec;
        }
        if(maxMidSumRec>maxSum){
            maxSum=maxMidSumRec;
        }
        return maxSum;
    }
    public static void main(String[] args) {
        int a[]={4,-3,5,-2,-1,2,6,-2};
        System.out.println(maxSumRec(a,0,7));
    }
}

三、动态规划算法

算法思想:

运用了动态规划的思想来解决最大子段和问题:
通过遍历累加这个数组元素,定时的更新最大子段和,
如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。

时间复杂度:O(n)

算法实现(Java):

package com.Third;
/*
 * 这是运用了动态规划的思想来解决最大子段和问题:
 * 通过遍历累加这个数组元素,定时的更新最大子段和,
 * 如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。
 */
public class Main1{
   public static int maxSubSum1(int []a){
       int maxSum=0; int nowSum=0;
       for(int i=0;i<a.length;i++){
           nowSum=nowSum+a[i];
           if(nowSum>maxSum){//更新最大子段和
               maxSum=nowSum;
           }
           if(nowSum<0){//当当前累加和为负数时舍弃,重置为0
               nowSum=0;
           }
       }
       return maxSum;
   }
   public static void main(String[] args) {
       int a[]={4,-3,5,-2,-1,2,6,-2};
       System.out.println(maxSubSum1(a));
   }
}
时间: 2024-08-08 22:07:49

关于求最大子段和的几种算法的相关文章

常见算法:C语言求最小公倍数和最大公约数三种算法

最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们的公倍数,当中一个最小的公倍数是他们的最小公倍数,相同地,若干个整数公有的倍数中最小的正整数称为它们的最小公倍数,维基百科:定义点击打开链接 求最小公倍数算法: 最小公倍数=两整数的乘积÷最大公约数 求最大公约数算法: (1)辗转相除法 有两整数a和b: ① a%b得余数c ② 若c=0,则b即为两数的最大公约数 ③ 若c≠0,则a=b,b=c,再回去运行① 比如求27和15的最大公约数过程为: 27÷15 余1215÷12余312÷3余0

C语言求最小公倍数和最大公约数三种算法(经典)

把以前写的一些经验总结汇个总,方便给未来的学弟学妹们做个参考! --------------------------永远爱你们的:Sakura 最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们的公倍数,其中一个最小的公倍数是他们的最小公倍数,同样地,若干个整数公有的倍数中最小的正整数称为它们的最小公倍数,维基百科:定义点击打开链接 求最小公倍数算法: 最小公倍数=两整数的乘积÷最大公约数 求最大公约数算法: (1)辗转相除法 有两整数a和b: ① a%b得余数c ② 若c=0,则b即为两

[C++]用三种方法求最大子段和

问题描述:给定n个整数组成的序列,求其中子段和的最大值.当所有整数均为非负整数时定义其最大子段和为0 方法一:O(n2)用一个值存储最大和,用枚举所有和的方法,来与这个值比较并更新最大值. 1 int MaxSum(int n, int *a, int &besti, int &bestj) 2 { 3 int sum=0; 4 for(int i=0;i<n;++i) 5 { 6 int parts=0; 7 for(int j=i;j<n;++j) 8 { 9 parts+

谈谈&quot;求线段交点&quot;的几种算法(js实现,完整版)

"求线段交点"是一种非常基础的几何计算, 在很多游戏中都会被使用到. 下面我就现学现卖的把最近才学会的一些"求线段交点"的算法总结一下, 希望对大家有所帮助. 本文讲的内容都很初级, 主要是面向和我一样的初学者, 所以请各位算法帝们轻拍啊 嘎嘎 引用 已知线段1(a,b) 和线段2(c,d) ,其中a b c d为端点, 求线段交点p .(平行或共线视作不相交) =============================== 算法一: 求两条线段所在直线的交点, 再

求线段交点&quot;的几种算法(js实现,完整版)

"求线段交点"是一种非常基础的几何计算, 在很多游戏中都会被使用到. 下面我就现学现卖的把最近才学会的一些"求线段交点"的算法说一说, 希望对大家有所帮助. 本文讲的内容都很初级, 主要是面向和我一样的初学者, 所以请各位算法帝们轻拍啊 嘎嘎 引用 已知线段1(a,b) 和线段2(c,d) ,其中a b c d为端点, 求线段交点p .(平行或共线视作不相交) 算法一: 求两条线段所在直线的交点, 再判断交点是否在两条线段上. 求直线交点时 我们可通过直线的一般方程

CODEVS 3981(求最大子段和+线段树)

题目链接:http://codevs.cn/problem/3981/ 参考:https://blog.csdn.net/jokingcoder/article/details/81477253 一个区间的最大子段和有三种情况: 1.等于这个区间左儿子的最大子段和 2.等于这个区间右儿子的最大子段和 3.等于这个区间左儿子的后缀最大子段和+右儿子的前缀最大子段和 tree[k].sumax = max(max(tree[l].sumax,tree[r].sumax),tree[l].rmax +

求逆元的四种算法(拓欧费马小线性推欧拉)

求逆元的四种算法 拓展欧几里得算法求逆元 上一篇博客中已经讲过拓展欧几里得算法,并且讲解了求逆元的原理.这里只列出代码 在要求逆元的数与p互质时使用 代码 //扩展欧几里得定理 int ex_gcd(int a,int b,int& x,int& y) { if(b==0) { x=1; y=0; return a; } int ans = ex_gcd(b,a%b,x,y); int tmp = x; x = y; y = tmp-a/b*y; return ans; } int cal

最近公共祖先(三种算法)

最近研究了一下最近公共祖先算法,根据效率和实现方式不同可以分为基本算法.在线算法和离线算法.下面将结合hihocoder上的题目分别讲解这三种算法. 1.基本算法 对于最近公共祖先问题,最容易想到的算法就是从根开始遍历到两个查询的节点,然后记录下这两条路径,两条路径中距离根节点最远的节点就是所要求的公共祖先. 题目参见 #1062 : 最近公共祖先·一 附上AC代码,由于记录的方式采取的是儿子对应父亲,所以实现的时候有点小技巧,就是对第一个节点的路径进行标记,查找第二个节点的路径时一旦发现访问到

算法导论-求(Fibonacci)斐波那契数列算法对比

目录 1.斐波那契数列(Fibonacci)介绍 2.朴素递归算法(Naive recursive algorithm) 3.朴素递归平方算法(Naive recursive squaring) 4 .自底向上算法(Bottom-up) 5. 递归平方算法(Recursive squaring) 6.完整代码(c++) 7.参考资料 内容 1.斐波那契数列(Fibonacci)介绍 Fibonacci数列应该也算是耳熟能详,它的递归定义如上图所示. 下面2-6分别说明求取Fibonacci数列的