Leetcode 053 最大子序和 python 分治+动态规划

2023-12-25 06:58

本文主要是介绍Leetcode 053 最大子序和 python 分治+动态规划,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

 

思路:

首先我们分析题目,我们思考,为什么最大和的连续子数组不包含其他的元素而是这几个呢?因为如果我们想在现有的基础上去扩展当前连续子数组,相邻的元素是一定要被加入的,而相邻元素中可能会减损当前的和。

思路一:

遍历法,On:

算法过程:遍历数组,用onesum去维护当前元素加起来的和。当onesum出现小于0的情况时,我们把它设为0。然后每次都更新全局最大值。

class Solution:def maxSubArray(self, nums):""":type nums: List[int]:rtype: int"""#onesum维护当前的和onesum = 0maxsum = nums[0]for i in range(len(nums)):onesum += nums[i]maxsum = max(maxsum, onesum)#出现onesum<0的情况,就设为0,重新累积和if onesum < 0:onesum = 0return maxsum

算法证明:一开始思考数组是个空的,把我们每次选一个nums[i]加入onesum看成当前数组新增了一个元素,也就是用动态的眼光去思考。过程很简单,代码很短,但为什么这样就能达到效果呢?我们进行的加和是按顺序来的,从数组第一个开始加。

当我们的i选出来后,加入onesum。这时有2种情况

1)假设我们这个onesum一直大于0,从未被<0过。那也就是说我们计算的每一次的onesum都大于0,而每一次计算的onesum都是包括开头元素的一段子序列(尾部一直随i变化)。看似我们没有考虑所有可能序列,但实际上所有可能的序列都已经被考虑过了。这里简单讲一下,待会po原文。

   a)以当前子序列开头为开头,中间任一处结尾的序列。这种情况是一直在扫描的,也有一直保存更新,所以不用怕丢失信息。

   b)以当前子序列结尾为结尾,中间任一处开头的序列。这种情况一定的和小于以当前子序列开头为开头,结尾为结尾的序列。因为前面缺失的那一段经过我们的前提,它也是加和大于0的。

   c)以中间元素为开头和结尾的序列。和小于以当前子序列开头为开头,此分序列结尾为结尾的序列。因为前面缺失的那一段经过我们的前提,它也是加和大于0的。

 

2)出现小于0的情况,就说明我们当前形成的这个子序是第一次出现小于0的情况。现在至少我们要新形成的连续数组不能在整个的包括之前的连续子序了,因为我们在之前的那个连续子序里加出了<0的情况。但问题是我们需不需要保留一些呢?是不是所有以当前子序结尾为结尾的任意开头的子序都要被舍弃呢?答案是是的,因为那一段也一定小于0,因为那一段的加和会小于以当前子序开头为开头,当前子序结尾为结尾的序列(见前面证明)。于是抛弃掉它们,重新开始新的子序。

 

思路二:

动态规划 On

算法过程:

设sum[i]为以第i个元素结尾的最大的连续子数组的和。假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第i个元素,即sum[i]
= max(sum[i-1] + a[i], a[i])。可以通过判断sum[i-1] + a[i]是否大于a[i]来做选择,而这实际上等价于判断sum[i-1]是否大于0。由于每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小

 


class Solution:def maxSubArray(self, nums):  """ :type nums: List[int] :rtype: int """  length=len(nums)  for i in range(1,length):  #当前值的大小与前面的值之和比较,若当前值更大,则取当前值,舍弃前面的值之和  subMaxSum=max(nums[i]+nums[i-1],nums[i])  nums[i]=subMaxSum#将当前和最大的赋给nums[i],新的nums存储的为和值  return max(nums)

算法证明:这道题的代码我直接使用了题目数据中的nums数组,因为只要遍历一遍。nums[i]表示的是以当前这第i号元素结尾(看清了一定要包含当前的这个i)的话,最大的值无非就是看以i-1结尾的最大和的子序能不能加上我这个nums[i],如果nums[i]>0的话,则加上。注意我代码中没有显式地去这样判断,不过我的Max表达的就是这个意思,然后我们把nums[i]确定下来。

 

思路三:

分治递归

算法过程:

分治法,最大子序和要么在左半部分,要么在右半部分,要么就横跨两部分(即包括左半部分的最后一个元素,和右半部分的第一个元素)。返回这三种情况的最大值即可。第三种情况,其中包括左半部分最后一个元素的情形,需要挨个往前遍历,更新最大值。包含右半部分的第一个元素的情况类似。总的时间复杂度O(nlogn)

 

class Solution(object):def maxSubArray(self, nums):#主函数left = 0#左右边界right = len(nums)-1#求最大和maxSum = self.divide(nums,left,right)return maxSumdef divide(self,nums,left,right):#如果只有一个元素就返回if left==right:return nums[left]#确立中心点center = (left+right)//2#求子序在中心点左边的和leftMaxSum = self.divide(nums,left,center)#求子序在中心点右边的和rightMaxSum = self.divide(nums,center+1,right)#求子序横跨2边的和,分成左边界和和右边界和leftBorderSum = nums[center]leftSum = nums[center]for i in range(center-1,left-1,-1):leftSum += nums[i]if leftSum>leftBorderSum:#不断更新左区块的最大值leftBorderSum = leftSumrightBorderSum = nums[center+1]rightSum = nums[center+1]for i in range(center+2,right+1):rightSum += nums[i]if rightSum>rightBorderSum:#不断更新右区块的最大值rightBorderSum = rightSum#左边界的和 + 右边那块的和BorderSum = leftBorderSum + rightBorderSumreturn max(leftMaxSum,rightMaxSum,BorderSum)

算法证明:

总的来说还是超级巧妙的。不断的切不断的切数组,把一块数组看成左中右三个部分。实际上这有点像枚举,但我们在枚举时利用了二分的思路,优化了很多。所以枚举当然可以达到我们的目标了,因为我们不断在计算以一定包括中间节点的子序的最大和。

 

总结:

今天写了很多很多,都没时间复习了。。。但是收获还是很大的。比如动态规划,不一定一定要建立数组然后返回数组的最后一项,动态规划其实是很灵活的。但是动态规划的每一项代表的意义要想好。

分治递归,实际在帮我们算所有数组只不过用了二分的思路优化。

 


作者:我喝酸奶不舔盖
来源:CSDN
原文:https://blog.csdn.net/weixin_41958153/article/details/81131379

这篇关于Leetcode 053 最大子序和 python 分治+动态规划的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python安装Pandas库的两种方法

《Python安装Pandas库的两种方法》本文介绍了三种安装PythonPandas库的方法,通过cmd命令行安装并解决版本冲突,手动下载whl文件安装,更换国内镜像源加速下载,最后建议用pipli... 目录方法一:cmd命令行执行pip install pandas方法二:找到pandas下载库,然后

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

Python进行JSON和Excel文件转换处理指南

《Python进行JSON和Excel文件转换处理指南》在数据交换与系统集成中,JSON与Excel是两种极为常见的数据格式,本文将介绍如何使用Python实现将JSON转换为格式化的Excel文件,... 目录将 jsON 导入为格式化 Excel将 Excel 导出为结构化 JSON处理嵌套 JSON:

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统