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

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

相关文章

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

nginx 负载均衡配置及如何解决重复登录问题

《nginx负载均衡配置及如何解决重复登录问题》文章详解Nginx源码安装与Docker部署,介绍四层/七层代理区别及负载均衡策略,通过ip_hash解决重复登录问题,对nginx负载均衡配置及如何... 目录一:源码安装:1.配置编译参数2.编译3.编译安装 二,四层代理和七层代理区别1.二者混合使用举例

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系