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


    一、比较朴素的算法

    算法思想:我们确定每个子段和开始的位置,分别为第一个,第二个,第三个......第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));
       }
    }
  • 相关阅读:
    ab(http)与abs(https)压测工具
    Q_DECLARE_PRIVATE与Q_DECLARE_PUBLIC
    QMetaObject::connectSlotsByName
    使用QStringBuilder进行字符串连接
    源码必须是UTF-8,QString需要它
    Qt开发中文显示乱码
    qDebug 的使用
    qt 4.6 qmake Reference
    qmake-variable-reference
    Qt学习网站
  • 原文地址:https://www.cnblogs.com/xiaotiaosi/p/6832637.html
Copyright © 2020-2023  润新知