关注微信公众号“酸痛鱼”,获得更多最新最全的文章。

本文中所涉及的代码,在未特殊声明的情况下,都是基于Python3程序设计语言编写的。

建议您在PC浏览器中阅读本文,以获得更好的阅读体验。

如果您未掌握知识提要中的内容,建议您先掌握这些内容之后再阅读本文。

知识提要

1、内置函数max、range、len

2、贪心算法

3、动态规划

4、分治法

5、时间复杂度、空间复杂度

0

最大子序和

因为Python切片语法中,array[i:j]表示从第i个元素到第j个元素(不包含j)的子 集。在本文所有表述中,我们将沿用这个语言规则,并不再额外说明。

给定一个数组array,其长度为n。对于任意非负整数i和j,满足0<=i

如果array是一个整数数组,我们将array[i:j]中所有元素的和称为array在i与j间的子序和。我们将值最大的子序和称为最大子序和。

例如:

输入:[1, 2, 3]

输出:6

输入:[-1, -2, -3]

输出:-1

解释:最大子序是[-1]

输入:[-4, 2, -1, 2, -1]

输出:3

解释:最大子序为[2, -1, 2]

本课题所有文章的特点是,尝试从多种角度,利用多种方法去解答一个题目。贪心算法是本题最简单且最优化的解法。如果你对其它几种解法不太理解,也没有关系,可以把阅读的重心放在贪心算法的解题思路上。

1

最大前缀和

对于下标i,以i为终点的子序有array[0:i+1], array[1:i+1], array[2,i+1], …, array[i,i+1]。我们将这些子序中,和最大者,称为i的最大前缀和,记为S(i)。

还是再强调一下,我们沿用了Python的语法,所以这些子序都不包含array[i+1]。我们将在下文中不停用到最大前缀和,并直接用S(i)表示,所以请先务必理解S(i)的含义。

2

直观解法

假设我们已经求得一个局部子序和cur_sum,它是array[i:j]的和,也就是cur_sum=S(j-1),且只考虑cur_sum>=0的情况。我们用max_sum保存全局最优解。那么对于下一个元素,只需考虑并处理两种如下情况:

A、如果array[j]>=0,那么我们array[i:j+1]必是一个更优解;于是我们可以把array[j]累加到cur_sum中,保存cur_sum与max_sum之较大者到max_sum,并继续往前走。相当于如果array[j] >= 0, S(j) = S(j-1) + S(j)。

B、如果array[j]<0,那么cur_sum必是一个局部最优解,保存cur_sum与max_sum之较大者到max_sum。之后,我们将array[j]累加到cur_sum上,如果cur_sum>=0,那么可以断续向前探索;如果cur_sum<0,则放弃array[i:j+1]的结果,即令cur_sum=0,并从array[j+1]开始探索。

当然了,因为我们的题目并没有要求我们输出i和j的值,只需要返回最大的cur_sum,即max_sum,所有我们的代码中并不需要记录i和j。由于只遍历了一遍array,所以此解法的时间复杂度为O(N)。

此解法虽然叫直观解法,但它需要处理多个边界条件,并在每次修改cur_sum后,判定是否要将cur_sum替换到max_sum。不仅如此,还需要考虑max_sum与array[j]的大小关系。不过为了体现后面解题思路的巧妙性,我还是尝试并实现了这种解法。如果你不太理解上面的描述,或者不太理解以下的代码,请不要太纠结。我在编写这个代码的时候,也是经常几次修改,才最终把各种边界条件处理妥当的。

def maxSubArraySum(array):

if not array:

return 0

max_sum = array[0]

cur_sum = 0

for v in array:

if v >= 0:

cur_sum += v

max_sum = max(max_sum, cur_sum)

else:

if cur_sum > 0:

max_sum = max(max_sum, cur_sum)

elif v > max_sum:

max_sum = v

cur_sum += v

if cur_sum < 0:

cur_sum = 0

return max_sum

3

贪心算法

贪心算法是一个更为容易理解的思路。假设我们已经求得一个局部子序和cur_sum,其初始值是array[0]。对于每第i个元素,cur_sum与cur_sum+array[i]的较大者,就是处理完元素i之后的局部最优解。每次用max_sum存储max_sum和cur_sum之较大者,最终就可以得到全局最优解。

总结成人话就是:S(i)=max(S(i), S(i-1) + array[i])

def maxSubArraySum(array):

if not array:

return 0

max_sum = array[0] # 全局最优解

cur_sum = max_sum # 局部最优解

for i in range(1, len(array)):

v = array[i]

cur_sum = max(v, cur_sum + v)

max_sum = max(max_sum, cur_sum)

return max_sum

4

动态规划

动态规划最在局部最优解中求得全局最优解的通用方法。

动态规划和贪心算法最大的区别在于,贪心算总是只记录当前局部最优解和全局最优解;而动态规划则记录所有的局部最优解。由于巧合,本题目用贪心算法和动态规则的代码实现很接近,但读者要明白它们的核心思路和应用场景是不一样的。

我们用长度为n的数组solution来存储我们的最大前缀和,即solution[i]=S(i);数组solution中最大的值,就是我们的解。

当然了,其实我们并不需要真的创建一个solution数组来存储局部解,我们可以在计算过程中不停地改变array[i]值,用array[i]来存储solution[i]即可。不过为了方便理解,我们还是会在代码中引入solution。读者把solution替换成array,一样可以得到正确的解。

def maxSubArraySum(array):

if not array:

return 0

solution = array[:] # solution[i] 保存0到i为止的局部最优解

for i in range(1, len(array)):

solution[i] = max(solution[i - 1] + array[i], array[i])

return max(solution)

上面的解法中,最后一行代码 return max(solution)对solution进行了一次遍历,找到最大的S(i)以得到最终的解。但事实上,我们在求解solution的每个元素的过程中,就可以顺便把最终的解记录下来,以减少最后面的遍历操作。优化之后的代码如下:

def maxSubArraySum(array):

if not array:

return 0

solution = array[:] # solution[i] 保存0到i为止的局部最优解

max_sum = array[0] # 全局最优解

for i in range(1, len(array)):

solution[i] = max(solution[i - 1] + array[i], array[i])

max_sum = max(max_sum, solution[i])

return max_sum

对比贪心算法,这个优化过的动态规划实现的代码跟贪心算法很像,大家肯定会觉得solution多此一举。的确是如此,我们再优化一下,把solution去掉,就是贪心算法的实现了。

5

分治法

将一个大问题,分解成一系列子问题,并将这些子问题合并得到最终的解。分治法在不同的应用场景中,解题思路稍微有一些不同。但基本的要求都是要可以将一个问题分成若干子问题来求解,并在这些子问题中可以求得或者合并成最终的解。

套用到我们的题目中,其基本思路是:

对于array的子集array[left:right],给定下标m(left<=m

1、左子集array[left:m+1] 中的最优解(分治左子集)

2、右子集array[m+1:right]中的最优解(分治右子集)

3、flank_sum

在实际解题的过程中,我们可以将array两等分成左右两个子集求解;其左右子集再以同样的思路再进一步切分求解。所以我们需要用到递归的方式。分治法的时间复杂度为O(NlogN),空间复杂度为O(logN)。

def flankSum(array, left, right, p):

# 在 [left, right]范围内,求包含P元素的最大连续子序和

#

if left == right:

return array[left]

left_sum = array[p]

cur_sum = 0

for i in range(p, left - 1, -1):

cur_sum += array[i]

left_sum = max(left_sum, cur_sum)

right_sum = array[p + 1]

cur_sum = 0

for i in range(p + 1, right + 1):

cur_sum += array[i]

right_sum = max(right_sum, cur_sum)

return left_sum + right_sum

def devideAndConquer(array, left, right):

if left == right:

return array[left]

p = (left + right) // 2

left_result = devideAndConquer(array, left, p) # 分治求P左侧的解

right_result = devideAndConquer(array, p + 1, right) # 分治求P右侧的解

flank_sum = flankSum(array, left, right, p) # 求含P元素的最大连续子序和

return max(left_result, right_result, flank_sum)

def maxSubArraySum(array):

size = len(array)

if size <= 1: array[0]

return devideAndConquer(array, 0, size - 1)

● 扫码关注我嗄嘎嘎

酸痛鱼,与你分享快乐的代码

python3和5_Python3算法之五:最大子序和相关推荐

  1. C++ 算法设计 最大子序和问题

    测试用例:1,2,3,4,-2,3,-5,6,-1,-1,1 答案:12 输出: 优化算法:12 普通算法:12 请按任意键继续. . . #include<iostream> using ...

  2. Java算法之最大子序和

    class Solution {public int maxSubArray(int[] nums) {int sum=0;int ret=Integer.MIN_VALUE;int len = nu ...

  3. LeetCode53:最大子序和(分治思想,Python3实现)

    最大子序和 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: ...

  4. leetcode - 53. 最大子序和 152. 乘积最大子序列 - 两个算法之间的联系和区别

    这两道算法题的解题思路是差不多的,但是从整体上分析,乘积最大子序列之和是最大子序和的进阶.先来看看两道算法题的简单描述. 53.最大子序和 给定一个整数数组 nums ,找到一个具有最大和的连续子数组 ...

  5. 力扣贪心算法专题(一)455.分发饼干 376. 摆动序列 53. 最大子序和 122.买卖股票的最佳时机II 1005.K次取反后最大化的数组和 思路及C++实现 贪心算法 动态规划

    文章目录 贪心算法 455.分发饼干 思路 步骤 代码 376. 摆动序列 贪心算法 思路 分析 代码 动态规划 思路 步骤 代码 53. 最大子序和 暴力解法 双层for循环 贪心算法 思路 分析 ...

  6. 伍六七带你学算法 入门篇 ——最大子序和

    力扣 53. 最大子序和 难度简单 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4 ...

  7. python【力扣LeetCode算法题库】53- 最大子序和

    最大子序和 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: ...

  8. LeetCode-53. 最大子序和-最简单的动态规划(Python3)

    题目链接: 53.最大子序和 题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,- ...

  9. [剑指offer]面试题第[42]题[Leedcode][JAVA][第53题][最大子序和][动态规划][贪心][分治]

    [问题描述][第53题][最大子序和][中等] 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和.示例:输入: [-2,1,-3,4,-1,2,1, ...

最新文章

  1. python 线程安全链表_教你用 Python 实现 HashMap 数据结构
  2. Bluetooth ATT介绍
  3. 新书首发 | 《机器学习 公式推导与代码实现》正式出版!(文末送书)
  4. bootstrap_bootstrap中日历范围选择插件daterangepicker的使用
  5. 腾讯“抢”小米黑鲨做元宇宙?
  6. conda安装tensorflow-gpu简洁版_【DP系列教程02】DeePMDkit:conda安装 amp; 离线安装
  7. [转]恢复 git reset -hard 的误操作
  8. python3.x中pip升级报错
  9. EasyUI笔记(六)数据表格
  10. 【图像隐写】基于matlab GUI DCT数字水印嵌入+提取【含Matlab源码 1671期】
  11. iOS 录音功能实现
  12. 网络安全--通过握手包破解WiFi(详细教程)
  13. 学习云计算需要哪些软件,需要什么知识面?
  14. matlab兔子问题,【matlab】狼追击兔子问题的建模
  15. “M1芯片”电脑杀手:Windows笔记本电脑目前岌岌可危
  16. 计算机临时保存信息,Windows临时文件夹是什么,Windows临时文件夹保存位置在哪里?...
  17. 自定义Android视频播放器 - 切换横竖屏
  18. cJSON详细剖析(四)----cJSON_Print()函数
  19. 如何免费获取IEEE论文,亲测有效,【分享给有需要的人】
  20. nginx反向代理实现二级域名转一级域名

热门文章

  1. 帝国cms 会员中心2.0
  2. word如何弄成两竖列_word分栏后成了竖行
  3. 5.4 创建 WBS
  4. 可扩展标记语言XML(淅淅沥沥的小雨)
  5. 如何查看电脑的操作系统以及更改计算机名称
  6. 阿里妈妈称日均覆盖人数破7000万
  7. 《可穿戴创意设计:技术与时尚的融合》一一3.4 服装中的电子装置
  8. android sqlite动态创建表,QT下如何实现SQLite动态创建表
  9. 人人都是网站分析师(从分析师视角理解网站和解读数据)-读书笔记4(完结)
  10. 【复】一次流量分析经历