最大子列和问题(JAVA)

最大子列和

问题描述:给定N个整数的序列{A1,A2,A3,…,An},求解子列和中最大的值。

这里我们给出{-2,11,-4,13,-5,-2}这样一个序列,正确的最大子列和为20

该题是在数据结构与算法中经常用于分析时间复杂度的典型题目,以下将给出四种方法来求解


一、三层循环——穷举法

(时间复杂度O(N^3))
这种方法的思路就是将每一个子列和都求出来,然后找出最大子列和

法1示例

public static int maxSubSum1(int[] arr){//设置整体最大值int maxSum = 0;//穷举法遍历//循环大小:Nfor( int i = 0;i<arr.length;i++ ){//循环大小:N-ifor(int j = i;j<arr.length;j++){//设置当前最大值int thisSum = 0;//求解arr[i]~arr[j]的最大值//循环大小:j-i+1for(int k = i;k<=j;k++){thisSum += arr[k];}//更新最大值if(thisSum > maxSum){maxSum = thisSum;}}}return maxSum;}

这种做法包含了三个循环,第一个循环的大小为N,第二个循环的大小为N-i,第三个循环的大小为j-i+1,根据时间复杂度的计算方法我们这里都可以看成N,所以时间复杂度为O(n^3)

二、两层循环——穷举法优化

(时间复杂度O(N^2))

这种算法是对以一种情况的优化,但是仍然属于穷举法,示例图和第一种方法一样,这里不再重复给出。

    public static int maxSubSum2(int[] arr){//设置整体最大值int maxSum = 0;//穷举法遍历//循环大小Nfor(int i = 0;i < arr.length;i++){int thisSum = 0;//循环大小N-ifor(int j = i;j<arr.length;j++){//直接进行累加,改进不必要的第三重循环thisSum += arr[j];if( thisSum > maxSum ){maxSum = thisSum;}}}return maxSum;}

观察第一种方法我们可以发现,第三层循环虽然尽可能优的列出了所有的情况,但是这种做法是可以进行优化的,按照问题描述,如果我们去除第三重循环,仍然可以实现穷举所有的情况,算法的时间复杂度变为O(n^2)

三、分治思想——递归法

(时间复杂度O(N·logN))

分治思想(divide-and-conquer)的基本思路是:把问题分成两个大致相等的子问题,然后递归地对它们求解,这是“分”的思想;“治”阶段将两个子问题的解修补到一起并可能再做些少许的附加工作,最后得到整个问题的解。

通过这种思想,最大子列和有可能出现在三个地方,左半段、右半段、交界处。
前两种情况可以通过递归求解,而第三种情况需要求出左半段带边界(即含有最后一个元素)的最大和以及右半段带边界(即含有第一个元素)的最大和而得到。

本题中,将序列从中间分开,分别求两部分的最大值。由此可见左边最大的为11,右边最大的为13,而交界处最大和需要通过左半段带边界的最大和,与右半段带边界的最大和,求和。(此处不易理解,读者可以根据图示中的绿色部分辅助理解,图中的绿色部分就是符合交界处序列和的值,左边最大值为7,右边最大值为13,和为20),综上比较,该序列的最大序列和为20

法3示例

    public static int maxSubSum3(int[] arr){//将数组arr,数组的下限0,数组的上限arr.length-1传入递归函数return maxSubSumRec(arr,0,arr.length-1);}//递归函数private static int maxSubSumRec(int[] arr,int left,int right){//当 left==right 时说明只有一个元素,并且当该元素非负时就是他的最大子序列if(left == right){if(arr[left] > 0){return arr[left];}else {return 0;}}//递归定义部分int center = ( left + right) / 2;int maxLeftSum = maxSubSumRec(arr,left,center);int maxRightSum = maxSubSumRec(arr,center+1,right);//递归实现部分int maxLeftBorderSum = 0;int leftBorderSum = 0;for(int i = center;i>=left;i--){leftBorderSum += arr[i];if(leftBorderSum > maxLeftBorderSum){maxLeftBorderSum = leftBorderSum;}}int maxRightBorderSum = 0;int rightBorderSum = 0;for(int i = center + 1;i<=right;i++){rightBorderSum += arr[i];if(rightBorderSum > maxRightBorderSum){maxRightBorderSum = rightBorderSum;}}//判断三者大小return max3(maxLeftSum,maxRightSum,maxLeftBorderSum + maxRightBorderSum);}//比较函数public static int max3(int a,int b,int c){int max;if(a>b){max = a;}else {max = b;}if(max>c){return max;}else {return c;}}

注:我们需要保存的不仅是左右两侧的最大序列和,还需要得到左右两侧带边界的最大序列和,这也就是为什么左侧循环从center往前遍历,而右侧循环从center+1往后遍历的原因,此顺序不可颠倒

这种方法乍看写了三个函数,实现该算法也需要更多的编程努力,但实际上程序代码量的多少与程序的效率根本并没有什么必然的联系。

该算法的时间复杂度为时间复杂度O(N·logN),效率明显高于前两种

四、一层循环——累计遍历法

(时间复杂度O(N))

这种方法,将循环减为一层,每次累加,并判断当前最大值(thisSum)与标准最大值(maxSum)的关系。

法4示例

虽然整体只进行了一趟循环,但是便于理解,在这里分成了6部分,每次更新thisSum的值并与maxSum比较。

    public static int maxSubSum4(int[] arr){int maxSum = 0;int thisSum = 0;for(int j = 0;j<arr.length;j++){thisSum += arr[j];if(thisSum > maxSum){maxSum = thisSum;}else if(thisSum < 0){thisSum = 0;}}return  maxSum;}

这种算法的效率是非常明显的,时间复杂度为O(N),这种方法可以算是近乎完美的一种求解最大子列和的算法。根据总结:任何负的子序列都不可能是最大子序列的前缀,所以可以知道,只要是首位元素为负数的肯定不是最大子列的组成部分。即如果某个子列的首位为负数,那么它一定要借助后面的非负数改进。
而且这种算法还有一种优点就是,它只对数据扫描一次,在任何时刻,算法都可以对它已经读入的数据给出正确的答案(具备这种特性的算法叫做联机算法)


下面是四种算法的在不同N情况下的时间复杂度情况:
算法时间复杂度
通过观察我们可以发现,在小量输入的情况下,几种算法的复杂度基本上都是眨眼之间能够完成的。但是在大量数据的情况下,我们可以看出,后两中算法仍然是能够在短时间内高效的完成同一件事,而前两种却显得异常乏力。



题外话:之前在暑假期间,利用C语言,完成了基本的数据结构算法博客的书写,虽然短时间内能够记住相关的算法,但是几个月来不经常接触,导致水平仍是停滞不前。鉴于现正在自学java,所以我将通过java来继续学习数据结构与算法这方面的知识。一方面可以通过撰文的形式加深记忆,另一方面,由于下学期学校会组织参加ACM大赛、数学建模大赛等比赛,一定要抽出足够的时间来学习算法。

才疏学浅,尚有诸多不懂之处,文章多有疏漏,还望前辈斧正。

本系列专栏所有的算法均参考Mark Allen Weiss先生的《数据结构与算法分析–Java语言描述》第三版。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569873.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

密码验证

用户在创建一个账户时&#xff0c;需要设置一个密码。密码的复杂程度是安全的保障之一&#xff0c;但是有些用户在设置密码时&#xff0c;总是把密码设置的过于简单&#xff0c;导致用户账户的安全存在威胁。因此&#xff0c;为了提高用户账户的安全性&#xff0c;添加了一个Ja…

阿里云windows/Linux 服务器建站教程,附WordPress配置方法

声明&#xff1a;文章仅供学习使用&#xff0c;故采用了多处链接&#xff0c;如有侵权&#xff0c;请私信我&#xff0c;立删。 最近看到一个学长做的验证界面&#xff0c;很简单的两个文本输入框&#xff0c;但是能给我们群里的小伙伴们做题提供一个验证答案的途径&#xff0…

Maven修改默认仓库为阿里云仓库

Maven 仓库默认在国外&#xff0c; 国内使用难免很慢&#xff0c;我们可以更换为阿里云的仓库。 第一步:修改 maven 根目录下的 conf 文件夹中的 setting.xml 文件&#xff0c;在 mirrors 节点上&#xff0c;添加内容如下&#xff1a; <mirrors><mirror><id>…

apache启动错误 AH00072: make_sock: could not bind to address [::]:443

一、安装apche遇到问题 在电脑上win7系统中安装了wnmp&#xff08;nginxMySQLphp7.2&#xff09;后&#xff0c;想要在安装一套wamp&#xff08;apacheMySQLphp7.2&#xff09;。说做就做&#xff0c;wamp的安装就比较简单了&#xff1a;首先&#xff0c;直接下载apache的压缩包…

Page9:结构分解以及系统内部稳定和BIBO稳定概念及其性质[Linear System Theory]

内容包含系统能控性结构分解、系统能观测性结构分解以及系统结构规范分解原理&#xff0c;线性系统的内部稳定、BIBO稳定概念及其性质 转载于:https://www.cnblogs.com/ERFishing/p/10314720.html

Java集合类及常用数据结构

下面这个图示为JAVA的集合类关系图&#xff0c;没用用严格的UML&#xff0c;了解其中的关系即可&#xff0c;其中颜色强调的几个类为常用的集合类。

win7添加开机启动项

添加开机启动项 开始菜单->所有程序->有个“启动”目录&#xff0c;然后右击选择“打开”&#xff0c;之后把软件的快捷方式移动到此目录下&#xff0c;然后重启电脑&#xff0c;就可以了。 注意&#xff1a;如果修改了程序的安装目录&#xff0c;这里需要删除之前的快捷…

续PA协商过程

续PA协商过程 当sw3的接口恢复之后会发生2中情况。 ①sw3的G0/0/2口先发BPDU ②sw3的G0/0/3口先发BPDU sw3先发送BPDU sw3和sw1的交互过程&#xff1a; sw3的2口恢复后&#xff0c;sw3的所有接口&#xff08;除了边缘端口&#xff09;&#xff0c;变为DP&#xff08;discardi…

搜索算法(一)--DFS/BFS求解拯救同伴问题(JAVA)

拯救同伴问题 问题描述&#xff1a;假设有如下迷宫&#xff0c;求解从某一点出发到目标位置的最短距离 Input: 5 4 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 4 3 Output: 7 深度优先搜索&#xff08;DFS&#xff09; import java.util.Scanner;public class DF…

PHP7.2的安装与配置(win7)

1、PHP的安装 1&#xff09;、环境安装目录&#xff1a; C:/wamp/|——php|——php7.2|——Apache24|——mysql|——www2&#xff09;、下载 linux专用&#xff1a;http://www.php.net/downloads.php windows专用&#xff1a;http://windows.php.net/download/ 官网里Windo…

搜索算法(二)--DFS/BFS求解炸弹人问题(JAVA )

炸弹人问题 问题描述&#xff1a;小人可以在迷宫中任意地方放置一个炸弹&#xff0c;炸弹可以在以该点为中心的十字方向杀死怪物&#xff0c;但是触碰到墙之后不再能传递攻击。求将一个炸弹放在哪个位置可以杀死更多的怪物&#xff1f;&#xff1f; Input&#xff1a; 13 1…

could not find driver和PDO drivers = no value

could not find driver 使用ThinkPHP5.0.20&#xff08;win7apache2.4.41 php7.2.21MySQL5.7&#xff09;连接MySQL数据库时&#xff0c;报错&#xff1a; 然后使用phpinfo();查看了一下扩展&#xff0c;发现了问题&#xff08;PDO drivers 的值为 no value&#xff09;&…

搜索算法(三)--DFS/BFS求解宝岛探险问题(JAVA )

宝岛探险问题 问题描述&#xff1a;某片海域有诸多岛屿&#xff0c;用0表示海洋&#xff0c;1-9表示陆地&#xff0c;现给定一个岛屿上的坐标点&#xff0c;求解所在岛屿的面积 思路&#xff1a;显然这是一个搜索算法&#xff0c;即只要从当前坐标点开始遍历&#xff0c;每遍…

win7上修改MySQL数据库密码

一、通过命令行方式修改MySQL密码 1、方法一&#xff1a;用mysqladmin 格式&#xff1a;mysqladmin -u用户名 -p旧密码 password 新密码 实例&#xff1a;mysqladmin -uroot -pabc password 123456 2、方法二&#xff1a;用set password 首先&#xff0c;登录MySQL数据库。…

Python爬虫从入门到放弃(二十)之 Scrapy分布式原理

原文地址https://www.cnblogs.com/zhaof/p/7306374.html 关于Scrapy工作流程回顾 Scrapy单机架构 上图的架构其实就是一种单机架构&#xff0c;只在本机维护一个爬取队列&#xff0c;Scheduler进行调度&#xff0c;而要实现多态服务器共同爬取数据关键就是共享爬取队列。 这里重…

python-入门

Python入门 阅读目录 一 编程与编程语言二 编程语言分类三 主流编程语言介绍四 python介绍五 安装python解释器六 第一个python程序七 变量八 用户与程序交互九 基本数据类型十 格式化输出十一 基本运算符十二 流程控制之if...else十三 流程控制之while循环十四 流程控制之for循…

图论算法(一)--最短路径的DFS/BFS解法(JAVA )

最短路径–城市路径问题&#xff1a; 问题描述&#xff1a;求从1号城市到5号城市的最短路径长度 Input&#xff1a; 5 8 1 2 2 1 5 10 2 3 3 2 5 7 3 1 4 3 4 4 4 5 5 5 3 3 Output&#xff1a; 9 DFS import java.util.Scanner; public class minPath {stati…

win7安装composer

一、下载安装包 二、安装 1、双击安装包进行安装 2、安装选项&#xff0c;点击next 3、选择php.exe的路径 4、选择并next 5、代理 6、准备安装 7、信息 8、安装成功 9、测试是否安装成功 10、安装位置 11、密钥位置 12、添加路径到环境变量 13、配置国内镜…

图论算法(二)-最短路径的Dijkstra [ 单源 ] 和Floyd[ 多源 ] 解法(JAVA )

一、Dijkstra算法 问题描述&#xff1a;求一个点到任意个点的距离 思路&#xff1a;单源最短路径问题&#xff0c;使用Dijkstra算法 Input&#xff1a; 6 9 1 2 1 1 3 12 2 3 9 2 4 3 3 5 5 4 3 4 4 5 13 4 6 15 5 6 4 Output&#xff1a; 0 1 8 4 13 17 imp…

MySQL日志分析

一、MySQL日志简介 &#xff08;一&#xff09;、mysql日志的种类&#xff0c;一般来说&#xff0c;日志有五种&#xff0c;分别为&#xff1a; 错误日志&#xff1a;log_error (记录启动&#xff0c;运行&#xff0c;停止mysql时出现的信息)二进制日志&#xff1a;log_bin &…