最大子列和问题(Java语言实现)

简介: 最大子列和问题(Java语言实现)

最大子列和问题(Java语言实现)


一、问题描述:给定N个整数的序列{ A 1 , A 2 , . . . , A n } ,求函数image.png的最大值,即求A i 到A j 连续的一段子列和最大的值。例如:某序列为{-1,-2,5,6,-11,8},则其最大子列和为11.


二、问题分析::一个整数序列中,可以产生出无数个子列,每个子列的和一般不相同,在此我们要求最大的子列,显然负数范围的子列和我们就不会考虑在内,因此如果所得结果小于0的数,则返回0做为结束


三、Java语言实现:


1.算法1: 暴力求解法,使用三重循环来求解,数据量小的时候没有问题,但是一旦数据量大,运行时间会很长,因为其时间复杂度为:T(n)=O(n 3 ) ,这是非常之恐怖的!以下是实现代码,数据量大的时候不推荐使用


import java.util.Scanner;
//三重循环方式
public class MaxSubseqSum1 {
    public  static void main(String[] args){
        System.out.println("请输入整数列的大小:");
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [] A=new int[N];
        System.out.println("请输入整数列元素:");
        for (int i = 0; i < N; i++) {
            A[i]=input.nextInt();
        }
        System.out.println("整数列为:");
        for (int i = 0; i < N; i++) {
            System.out.print(" "+A[i]);
        }
        System.out.println();
        System.out.println("最大子列和为:"+MaxSubseqSum1.FindMaxSubseqSum1(A,N));
    }
    public  static int FindMaxSubseqSum1(int [] A,int N ) {
        int MaxSum=A[0];
        for (int i = 0; i < N; i++) {
            for (int j = i; j < N; j++) {
                int ThisSum = 0;
                for (int k = i; k < j; k++) {
                    ThisSum += A[k];
                }
                if (ThisSum > MaxSum) {
                    MaxSum = ThisSum;
                }
            }
        }
        return MaxSum;
    }
}

2.算法2: 改进的暴力求解法。思想:对于求和的问题,例如要求某数列的前n项和,我们可以采用前k项和 = 前k-1项和+第k项的方法来求解。于是可以将算法1的第三层循环进行改进,代码如下:

import java.util.Scanner;
public class MaxSubseqSum2 {
    public  static void main(String[] args){
        System.out.println("请输入整数列的大小:");
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [] A=new int[N];
        System.out.println("请输入整数列元素:");
        for (int i = 0; i < N; i++) {
            A[i]=input.nextInt();
        }
        System.out.println("整数列为:");
        for (int i = 0; i < N; i++) {
            System.out.print(" "+A[i]);
        }
        System.out.println();
        System.out.println("最大子列和为:"+MaxSubseqSum2.FindMaxSubseqSum2(A));
    }
    public static int FindMaxSubseqSum2(int [] A){
        int MaxSum=A[0];
        int ThisSum;
        for (int i = 0; i < A.length; i++) {
            ThisSum=0;
            for (int j = i; j < A.length; j++) {
                ThisSum+=A[j];    //改进
                if (ThisSum>MaxSum){
                    MaxSum=ThisSum;
                }
            }
        }
        return MaxSum;
    }
}

但是,这个算法还是使用了二重循环,数据量小的时候没有问题,但是一旦数据量大,运行时间会很长,因为其时间复杂度为:T(n)=O(n 2) 。算法2已经成功地将算法1的时间复杂度降了1阶,那我们还能不能继续将算法2的复杂度降低呢?显示是可以的!一名优秀的程序员,在得到时间复杂度为T(n)=O(n 2 )的算法之后,总是希望将时间复杂度降到T(n)=O(n l o g n )!


3.算法3: 分而治之


步骤:

1.将序列从中分为左右两个子列

2.递归求得两个子列的最大和

3.从子列的中分点分头向左右两边扫描,找出跨越分界线的最大子列和

4.输出这三个最大子列和中最大的一个

我也是第一次接触分治算法,理解还不是很透彻,后期再慢慢补吧,贴上代码:

import java.util.Scanner;
public class MaxSubseqSum3 {
    public static void main(String[] args){
        System.out.println("请输入整数列的大小:");
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [] A=new int[N];
        System.out.println("请输入整数列元素:");
        for (int i = 0; i < N; i++) {
            A[i]=input.nextInt();
        }
        System.out.println("整数列为:");
        for (int i = 0; i < N; i++) {
            System.out.print(" "+A[i]);
        }
        System.out.println();
        System.out.println("最大子列和为:"+MaxSubseqSum3.DivideAndConquer(A,0,A.length-1));
                                      //left为数组起点,right为数组中点.
    }
    public static int DivideAndConquer(int [] A,int left,int right){
        int MaxLeftSum,MaxRightSum;//存放左、右子列的最大子列和
        int MaxLeftBorderSum,MaxRightBorderSum;//存放跨分界线的左、右子列的最大子列和
        int leftBorderSum,rightBorderSum;//存放放跨分界线的左、右子列的子列和
        int center;//存放分点的下标
        //终止条件,子列只有一个数字
        if(left==right){
            if (A[left]>0){
                return A[left];
            }
            else
                return 0;
        }
        //分的过程
        center=(left+right)/2;
        MaxLeftSum=DivideAndConquer(A,left,center);//递归求左子列和
        MaxRightSum=DivideAndConquer(A,center+1,right);//递归求右子列和
        //求跨分界的最大子列和
        MaxLeftBorderSum=0;
        leftBorderSum=0;
        for (int j = center; j > left; j--) {
            leftBorderSum+=A[j];
            if (leftBorderSum>MaxLeftBorderSum){
                MaxLeftBorderSum=leftBorderSum;
            }
        }//左边扫描结果
        MaxRightBorderSum=0;
        rightBorderSum=0;
        for (int j = (center+1);  j < right; j++) {
            rightBorderSum+=A[j];
            if(rightBorderSum>MaxRightBorderSum){
                MaxRightBorderSum=rightBorderSum;
            }
        }//右边扫描结果
        return MaxSubseqSum3.FindMax(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);
    }
    public static int FindMax(int a,int b,int c){
        return (a>b)?((a>c)?a:c):((b>c)?b:c);
    }
}


分而治之算法的时间复杂度是T(n)=O(n l o g n nlognnlogn),已经是一个比较好的算法了,还有一个时间复杂度更低的算法

4.算法4:在线处理算法 思想:每扫描到一个元素,就求出和ThisSum,然后进行判断,如果ThisSum大于MaxSum,就更新MaxSum=ThisSum;如果ThisSum小于0,就直接令ThisSum=0;重复上述步骤,直到扫描完数组的所有元素,返回MaxSum。以下是代码实现:

import java.util.Scanner;
public class MaxSubseqSum4 {
    public static void main(String [] args){
        System.out.println("请输入整数列的大小:");
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [] A=new int[N];
        System.out.println("请输入整数列元素:");
        for (int i = 0; i < N; i++) {
            A[i]=input.nextInt();
        }
        System.out.println("整数列为:");
        for (int i = 0; i < N; i++) {
            System.out.print(" "+A[i]);
        }
        System.out.println();
        System.out.println("最大子列和为:"+MaxSubseqSum4.OnlineProcess(A));
    }
    public static int OnlineProcess(int [] A){
        int ThisSum=0,MaxSum=A[0];
        for (int i = 0; i < A.length; i++) {
            ThisSum+=A[i];
            if (ThisSum>MaxSum){
                MaxSum=ThisSum;
            }
            else if (ThisSum<0){
                ThisSum = 0;
            }
        }
        return MaxSum;
    }
}

时间复杂度仅为T(n)=O(n),所以这个算法以及非常快了,但有优点就有缺点,缺点就是它容易出错。


五、总结


还有最后6天就要到大三了,从昨天才开始系统的学习数据结构和算法,希望自己能够坚持下去,在学习Java开发的内容时也不要放弃了数据结构和算法的学习。我是先跟着慕课浙大数据结构来学习的,计划每天学习一节内容,并实现上面的算法。加油!

相关文章
|
13天前
|
IDE Java Unix
Java语言开发环境配置详解
Java语言开发环境配置详解
|
2天前
|
安全 Java API
Java一分钟之-GraphQL:查询语言与API设计
【6月更文挑战第11天】GraphQL,一种革命性的查询语言,正在改变Web开发中的API构建和使用方式。它允许客户端按需请求数据,减少冗余,提升性能。本文概述了GraphQL的核心理念,如声明式查询、强类型和统一入口,并讨论了Java开发者常遇问题:过度查询、Schema设计和安全性。解决方案包括使用Dataloader、优化Schema和实现授权机制。通过理解原理、关注性能、重视安全和持续实践,开发者能更好地利用GraphQL构建高效API。
11 2
|
5天前
|
机器学习/深度学习 Java 开发者
Python vs. Java:语言之争的终结
【6月更文挑战第8天】Python与Java,两种影响力巨大的编程语言,各有千秋。Python以简洁语法和强大库支持在数据科学、机器学习领域大放异彩,适合快速原型设计;而Java以其稳定性能、跨平台兼容性在大型系统、企业应用中占据一席之地。语言之争实为互补,开发者应根据项目需求选择合适工具,两者和谐共存,共同推动编程技术进步。
|
7天前
|
存储 设计模式 Java
Java语言中反射动态代理接口的解释与演示
Java语言中反射动态代理接口的解释与演示
7 1
|
7天前
|
算法 Java API
Base64编码介绍及基于Java语言实现
Base64编码介绍及基于Java语言实现
12 0
|
8天前
|
Java 容器
双指针(JAVA语言)
双指针(JAVA语言)
双指针(JAVA语言)
|
9天前
|
JavaScript 前端开发 Java
Go语言入门【java->go】
Go语言入门【java->go】
18 2
|
10天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的java语言的考试信息报名系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的java语言的考试信息报名系统附带文章源码部署视频讲解等
14 0
|
13天前
|
安全 Java API
Java语言的特点及其应用深度解析
Java语言的特点及其应用深度解析
24 1
|
13天前
|
安全 Java 编译器
深入理解Java语言中的方法重载(Overloading)
深入理解Java语言中的方法重载(Overloading)