从最大子列和问题看几种不同的算法思想

2023-11-01 01:38

本文主要是介绍从最大子列和问题看几种不同的算法思想,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首发地址:https://www.cnblogs.com/saw96x/p/12411966.html
题目描述
只看题目描述不看测试数据特点的话,第一眼能想到的算法无非就是利用遍历逐个相加,算出每一种可能的子列和,然后返回其中最大的子列和,看看代码如何实现

int MaxSumSeq(int a[],int len){int ThisSum=0,MaxSum=0;for(int i=0;i<len;i++){//子列的左端for(int j=i;j<len;j++){//子列的右端,循环实际上是左端一个个加,到右端为止,然后再移动左端ThisSum+=a[i];if(ThisSum>MaxSum)MaxSum=ThisSum;}}return MaxSum;
}

这个算法应该是比较容易想到的(不过小白笔者还是写了一小会555555),但这个代码的时间复杂度高达O(n2),对于测试数据来说,前两个可以还算快的跑完,但是3,4,5的数据量经过平方就变得非常恐怖了,所需要的时间也快速飙升,那么有没有复杂度更低的算法呢

int Max3( int A, int B, int C ){ /* 返回3个整数中的最大值 */return A > B ? A > C ? A : C : B > C ? B : C;}int DivideAndConquer( int List[], int left, int right ){ /* 分治法求List[left]到List[right]的最大子列和 */int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/int LeftBorderSum, RightBorderSum;int center, i;if( left == right )  { /* 递归的终止条件,子列只有1个数字 */if( List[left] > 0 )  return List[left];else return 0;}/* 下面是"分"的过程 */center = ( left + right ) / 2; /* 找到中分点 *//* 递归求得两边子列的最大和 */MaxLeftSum = DivideAndConquer( List, left, center );MaxRightSum = DivideAndConquer( List, center+1, right );/* 下面求跨分界线的最大子列和 */MaxLeftBorderSum = 0; LeftBorderSum = 0;for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */LeftBorderSum += List[i];if( LeftBorderSum > MaxLeftBorderSum )MaxLeftBorderSum = LeftBorderSum;} /* 左边扫描结束 */MaxRightBorderSum = 0; RightBorderSum = 0;for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */RightBorderSum += List[i];if( RightBorderSum > MaxRightBorderSum )MaxRightBorderSum = RightBorderSum;} /* 右边扫描结束 *//* 下面返回"治"的结果 */return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );}int MaxSubseqSum3( int List[], int N ){ /* 保持与前2种算法相同的函数接口 */return DivideAndConquer( List, 0, N-1 );}

那就是用经典的分而治之思想了,将总列分为左右两个子列,分别求他们的子列和与跨越中线的子列和,然后对于左右两边的子列,继续分为子列,继续求子列和和跨越中线的子列和······然后再依次返回其中的最大子列和,相加······这样的算法好处是时间复杂度大大减少,达到了O(nlog n),但当数据非常非常大的时候,可能由于递归次数过多导致栈溢出,程序不正常结束(对于快速排序和求子列和这种分而治之的问题一般达不到溢出的程度)

笔者一度认为这就是最高效的算法了,但今日又看到了新的更快的算法:在线处理

int MaxSumSeq(int a[],int len){int ThisSum=0,MaxSum=0;for(int i=0;i<len;i++){ThisSum+=a[i];if(MaxSum<ThisSum)MaxSum=ThisSum;if(ThisSum<0)ThisSum=0;}return MaxSum;
}

可以看到它更加精简,时间复杂度更低,只有O(n),这对比分而治之又是快了不少,那么它的实现原理是什么呢

从第一个数开始相加,当ThisSum小于0时,那么下一个数再怎么大,ThisSum肯定都不是最大子列和了,因为下一个数的值都减少了,就必然不可能时最大子列和了,因此就让ThisSum等于0,相当于重新开始算最大的子列和,只要ThisSum不小于0,那么下一个值加上它无论如何都不会变得更小。

为什么叫他在线处理呢,因为它每一步得到的子列和一定都是当前可以达到的最大的子列和,随着循环的进行,最大子列和不断的更新,循环结束后就得到了最大子列和。

这是笔者首次见到这种思想的算法,似乎只有KMP匹配算法和它有些许相似,不像分而治之的算法以前见过快速排序,希望以后能见到更多这种思想的算法,加深印象,拓宽思路。

这篇关于从最大子列和问题看几种不同的算法思想的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/319570

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

CSS去除a标签的下划线的几种方法

《CSS去除a标签的下划线的几种方法》本文给大家分享在CSS中,去除a标签(超链接)的下划线的几种方法,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧... 在 css 中,去除a标签(超链接)的下划线主要有以下几种方法:使用text-decoration属性通用选择器设置:使用a标签选择器,将tex

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Flutter打包APK的几种方式小结

《Flutter打包APK的几种方式小结》Flutter打包不同于RN,Flutter可以在AndroidStudio里编写Flutter代码并最终打包为APK,本篇主要阐述涉及到的几种打包方式,通... 目录前言1. android原生打包APK方式2. Flutter通过原生工程打包方式3. Futte

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Python实现Microsoft Office自动化的几种方式及对比详解

《Python实现MicrosoftOffice自动化的几种方式及对比详解》办公自动化是指利用现代化设备和技术,代替办公人员的部分手动或重复性业务活动,优质而高效地处理办公事务,实现对信息的高效利用... 目录一、基于COM接口的自动化(pywin32)二、独立文件操作库1. Word处理(python-d