-
动态规划套路:最大子数组和
2020-05-21 09:09:23点击上方蓝字设为星标东哥带你手把手撕力扣????点击下方卡片即可搜索????最大子数组问题和前文讲过的 经典动态规划:最长递增子序列 的套路非常相似,代表着一类比较特殊的动态规划问题的思...点击上方蓝字设为星标
东哥带你手把手撕力扣????
点击下方卡片即可搜索????
最大子数组问题和前文讲过的 经典动态规划:最长递增子序列 的套路非常相似,代表着一类比较特殊的动态规划问题的思路:
title 思路分析
其实第一次看到这道题,我首先想到的是滑动窗口算法,因为我们前文说过嘛,滑动窗口算法就是专门处理子串/子数组问题的,这里不就是子数组问题么?
但是,稍加分析就发现,这道题还不能用滑动窗口算法,因为数组中的数字可以是负数。
滑动窗口算法无非就是双指针形成的窗口扫描整个数组/子串,但关键是,你得清楚地知道什么时候应该移动右侧指针来扩大窗口,什么时候移动左侧指针来减小窗口。
而对于这道题目,你想想,当窗口扩大的时候可能遇到负数,窗口中的值也就可能增加也可能减少,这种情况下不知道什么时机去收缩左侧窗口,也就无法求出「最大子数组和」。
解决这个问题需要动态规划技巧,但是
dp
数组的定义比较特殊。按照我们常规的动态规划思路,一般是这样定义dp
数组:nums[0..i]
中的「最大的子数组和」为dp[i]
。如果这样定义的话,整个
nums
数组的「最大子数组和」就是dp[n-1]
。如何找状态转移方程呢?按照数学归纳法,假设我们知道了dp[i-1]
,如何推导出dp[i]
呢?如下图,按照我们刚才对
dp
数组的定义,dp[i] = 5
,也就是等于nums[0..i]
中的最大子数组和:那么在上图这种情况中,利用数学归纳法,你能用
dp[i]
推出dp[i+1]
吗?实际上是不行的,因为子数组一定是连续的,按照我们当前
dp
数组定义,并不能保证nums[0..i]
中的最大子数组与nums[i+1]
是相邻的,也就没办法从dp[i]
推导出dp[i+1]
。所以说我们这样定义
dp
数组是不正确的,无法得到合适的状态转移方程。对于这类子数组问题,我们就要重新定义dp
数组的含义:以
nums[i]
为结尾的「最大子数组和」为dp[i]
。这种定义之下,想得到整个
nums
数组的「最大子数组和」,不能直接返回dp[n-1]
,而需要遍历整个dp
数组:int res = Integer.MIN_VALUE; for (int i = 0; i < n; i++) { res = Math.max(res, dp[i]); } return res;
依然使用数学归纳法来找状态转移关系:假设我们已经算出了
dp[i-1]
,如何推导出dp[i]
呢?可以做到,
dp[i]
有两种「选择」,要么与前面的相邻子数组连接,形成一个和更大的子数组;要么不与前面的子数组连接,自成一派,自己作为一个子数组。如何选择?既然要求「最大子数组和」,当然选择结果更大的那个啦:
// 要么自成一派,要么和前面的子数组合并 dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]);
综上,我们已经写出了状态转移方程,就可以直接写出解法了:
int maxSubArray(int[] nums) { int n = nums.length; if (n == 0) return 0; int[] dp = new int[n]; // base case // 第一个元素前面没有子数组 dp[0] = nums[0]; // 状态转移方程 for (int i = 1; i < n; i++) { dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]); } // 得到 nums 的最大子数组 int res = Integer.MIN_VALUE; for (int i = 0; i < n; i++) { res = Math.max(res, dp[i]); } return res; }
以上解法时间复杂度是 O(N),空间复杂度也是 O(N),较暴力解法已经很优秀了,不过注意到
dp[i]
仅仅和dp[i-1]
的状态有关,那么我们可以进行「状态压缩」,将空间复杂度降低:int maxSubArray(int[] nums) { int n = nums.length; if (n == 0) return 0; // base case int dp_0 = nums[0]; int dp_1 = 0, res = dp_0; for (int i = 1; i < n; i++) { // dp[i] = max(nums[i], nums[i] + dp[i-1]) dp_1 = Math.max(nums[i], nums[i] + dp_0); dp_0 = dp_1; // 顺便计算最大的结果 res = Math.max(res, dp_1); } return res; }
最后总结
虽然说动态规划推状态转移方程确实比较玄学,但大部分还是有些规律可循的。
今天这道「最大子数组和」就和「最长递增子序列」非常类似,
dp
数组的定义是「以nums[i]
为结尾的最大子数组和/最长递增子序列为dp[i]
」。因为只有这样定义才能将dp[i+1]
和dp[i]
建立起联系,利用数学归纳法写出状态转移方程。_____________
公众号:labuladong
B站:labuladong
知乎:labuladong
fucking-algorithm 项目在 Github 上已破 42k star,即将出版,公众号后台回复关键词「pdf」限时免费下载,回复「进群」可加入刷题群。东哥手把手带你撕 LeetCode,感受支配算法的快感~
-
TCP/IP网络互联技术(卷3):客户-服务器编程与应用(Windows套接字版)--详细书签版
2013-06-27 07:31:35重点放在客户—服务器机制上,介绍了客户-服务器机制和应用程序用于网络通信的套接字接口,分析了分布式程序的客户端和服务器两部分的算法,讨论了客户端和服务器的设计及遵循的模式。本书在并发处理上也花费了相当... -
python sort() 从大到小_Python中的列表 VS C语言中的数组(下)
2021-01-31 09:50:56对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:...对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:整型数字,浮点型,字符串以及对象等。接下来将介绍如何向列表里面加元素、删减列表中的一些元素、 获取列表里面的特定元素、列表分片、常用的列表操作符、其他常见列表操作函数。
4、列表分片
对于列表分片的含义需要明白,列表分片就是指将列表里面的一些列元素(不仅仅是某一个元素)进行获取或者得到:temp=List[A:B] 表示将m列表里从索引号位置为A开始的元素到B-1处元素之间的列表获取赋给temp。
temp = List[1:3]print(temp)
5、常用的列表操作符
首先定义两个列表list1和list2。
list1 = [1,2,3,4,5,6,7,8,9]list2 = [98,76,54,32,1]
1)+:它主要实现的是多个列表之间的拼接常见的列表操作符
list3 = list1 + list2print(list3)
2)*:主要实现的是列表的复制和添加
list3 = list1*3
3)比较>,<:>
list1 > list2
4)and等:;逻辑运算符,可以进行列表之间的逻辑判断
list1 > list2 and list2 > list3
6、其他常见列表操作函数
1)count(A):输出元素A在列表list3里面出现的次数。
list3.count(1)
2)index(A):输出元素A在列表m里面的索引位置号list3.index(A,a,b):对于列表list3里面包含多个元素A时,输出在列表list3索引号a-b之间的特定索引号。
list3.index(1)
3)reverse():将列表list3进行前后的翻转,前变后,后变前。
list3.reverse()print(list3)
4)sort():将列表list3里面地数据进行从小到大的排列。
list3.sort()print(list3)
5)sort(reverse=True):将列表list3里面地数据进行从大到小的排列。
list3.sort(reverse=True)print(list3)
-
list选取多个元素 python_Python中的列表 VS C语言中的数组(上)
2020-12-30 17:01:28对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:...对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:整型数字,浮点型,字符串以及对象等。接下来将介绍如何向列表里面加元素、删减列表中的一些元素、 获取列表里面的特定元素、列表分片、常用的列表操作符、其他常见列表操作函数、列表的拷贝。
我们首先定义一个列表。
List = [1,2,3,4.56,'xiaoming']
1、 向列表里面加元素。
向列表中增加元素有三种方法:
第一种,append()函数。对于列表的操作主要实现的是在特定的列表最后添加一个元素,并且只能添加一个元素,并且只能在列表最后;【向列表最后添加一个元素“student”】。
List.append("student")
第二种,extend()函数。对于列表的操作主要实现的是对于特定列表的扩展和增长,可以一次添加多个元素,不过也只能添加在列表的最后;【向列表最后添加元素“A”、"B"、"C"】。
List.extend(['A','B','C'])
第三种,insert()函数对于列表的操作主要是在列表的特定位置添加想要添加的特定元素,比较常用。【向列表第一个位置添加元素“WelcomeToPython"】。
List.insert(0,'WelcomeToPython')
2、 删减列表中的一些元素。
与之前python列表的添加元素相对,删减列表里面的一些元素也有三种方法:
第一种,remove()函数,移除掉列表里面的特定元素;
List.remove("xiaoming")
第二种,操作语句del,删除掉列表里面的索引号位置为n的元素;
del List[0]
第三种,pop()函数,将列表的最后一个元素返回,并且在此基础上进行删除掉。
temp = List.pop()
3、 获取列表里面的特定元素。
temp=List[n] %获取List列表第n+1位置处的元素。
temp = List[1]print(temp)
-
c语言从文件中读取数据存入数组_Python中的列表 VS C语言中的数组(上)
2020-11-22 16:26:07对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:...对于python列表的理解可以和C语言里面的数组进行比较性的记忆与对照,它们比较相似,对于python里面列表的定义可以直接用方括号里加所包含对象的方法,并且python的列表是比较强大的,它包含了很多不同类型的数据:整型数字,浮点型,字符串以及对象等。接下来将介绍如何向列表里面加元素、删减列表中的一些元素、 获取列表里面的特定元素、列表分片、常用的列表操作符、其他常见列表操作函数、列表的拷贝。
我们首先定义一个列表。
List = [1,2,3,4.56,'xiaoming']
1、 向列表里面加元素。
向列表中增加元素有三种方法:
第一种,append()函数。对于列表的操作主要实现的是在特定的列表最后添加一个元素,并且只能添加一个元素,并且只能在列表最后;【向列表最后添加一个元素“student”】。
List.append("student")
第二种,extend()函数。对于列表的操作主要实现的是对于特定列表的扩展和增长,可以一次添加多个元素,不过也只能添加在列表的最后;【向列表最后添加元素“A”、"B"、"C"】。
List.extend(['A','B','C'])
第三种,insert()函数对于列表的操作主要是在列表的特定位置添加想要添加的特定元素,比较常用。【向列表第一个位置添加元素“WelcomeToPython"】。
List.insert(0,'WelcomeToPython')
2、 删减列表中的一些元素。
与之前python列表的添加元素相对,删减列表里面的一些元素也有三种方法:
第一种,remove()函数,移除掉列表里面的特定元素;
List.remove("xiaoming")
第二种,操作语句del,删除掉列表里面的索引号位置为n的元素;
del List[0]
第三种,pop()函数,将列表的最后一个元素返回,并且在此基础上进行删除掉。
temp = List.pop()
3、 获取列表里面的特定元素。
temp=List[n] %获取List列表第n+1位置处的元素。
temp = List[1]print(temp)
-
用TCP/IP进行网际互联 第三卷:客户-服务器编程与应用(Linux/POSIX套接字版)--详细书签版
2012-10-12 14:44:576.19 连接的和非连接的UDP套接字 52 6.20 对UDP使用connect 52 6.21 使用UDP与服务器通信 52 6.22 关闭使用UDP的套接字 53 6.23 对UDP的部分关闭 53 6.24 关于UDP不可靠性的警告 53 6.25 小结 53 深入研究 ... -
清华大学的计算机网络课件
2010-03-26 11:11:56问题1-13:如果用时延带宽积管道来比作传输链路,那么是否宽带链路对应的时延带宽积管道就比较宽呢? 问题1-14:网络的吞吐量与网络的时延有何关系? 问题1-15:什么是“无缝的”、“透明的”和“虚拟的”? 问题1-... -
微软 VB2010 源码包
2013-05-22 02:21:18ImplicitLCSamples:此示例包含两个具有相似源代码的源文件,这两个文件分别使用隐式和显式行继续符 StatementLambdasSample:通过 lambda 语句,可以用其他过程中的多个语句来声明过程 StringFormatting:演示... -
自己动手写操作系统(含源代码).part2
2010-10-18 19:47:45或许我应该把自己的经历写下来,从而可以帮助跟我相似的后来者,就这样,我编写了本书的第一版,也就是《自己动手写操作系统》。我相信,如果你也对神奇的计算机世界充满好奇,并且希望通过自己编写操作系统的方式来... -
自己动手写操作系统(含源代码).part1
2010-10-18 19:41:25或许我应该把自己的经历写下来,从而可以帮助跟我相似的后来者,就这样,我编写了本书的第一版,也就是《自己动手写操作系统》。我相信,如果你也对神奇的计算机世界充满好奇,并且希望通过自己编写操作系统的方式来... -
Linux操作系统基础教程
2013-04-08 21:34:26Linux的核心具有 Windows 无法比拟的稳定性和高效率,在不使用 X Windows 的情况 下,它占用系统资源较少,可以使一台 Intel486摇身一变成为高效工作站。对于想要学习 UNIX的用户来说,使他们熟悉 UNIX 操作环境,... -
C++MFC教程
2013-05-21 13:37:15例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。 2、谁将收到... -
哈佛大学职业经理MBA全套讲义
2008-10-08 19:15:54或许总有一天,现有的炉灶和取暖灶都会被比较节省天然气或是使用其他燃料的炉灶所取代。 表2.1.3 天然气的使用及其替代品 ───────────────────────────────────────... -
入门学习Linux常用必会60个命令实例详解doc/txt
2011-06-09 00:08:45这里笔者把比较重要和使用频率最多的命令,按照它们在系统中的作用分成下面六个部分一一介绍。 ◆ 安装和登录命令:login、shutdown、halt、reboot、install、mount、umount、chsh、exit、last; ◆ 文件处理命令... -
计算机网络常见问题解答
2010-06-07 08:19:11问题5-2:从通信的起点和终点来比较,TCP和IP的不同点是什么? 问题5-3:端口(port)和套接字(socket)的区别是什么? 问题5-4:一个套接字能否同时与远地的两个套接字相连? 问题5-5:数据链路层的HDLC协议和运输层的... -
软件工程-理论与实践(许家珆)习题答案
2011-01-12 00:49:42比较复杂的系统不能画在一张纸上,逐层分解的画法可以控制每一层的复杂度。 顶层:将整个系统作为一个加工,描述系统边界(输入与输出)。 中间层:表示某个加工分解为一组子加工,其中的子加工还需进一步分解。 ... -
煤炭地址问题解析解答详情
2011-06-20 11:53:49答:褶曲的基本形式只有背斜和向斜,但在自然界中背斜和向斜的形态又是多种多样,根据它们在横剖面、纵剖面和平面上的形态特征,可以进一步分类,褶曲在横剖面上的形态分类1)直立褶曲2)倾斜褶曲3)倒转褶曲褶曲在... -
软件工程教程
2012-07-06 23:10:29传统的手工方式对图书信息的管理已越来越不能适应社会发展的需要,尤其是随着计算机网络和Internet的普及,运用先进的信息管理系统对信息进行科学化和网络化管理,已成为图书信息管理系统发展的趋势。 系统的研发... -
图像处理基础(第2版).[美]Maria Petrou(带详细书签).pdf
2019-01-05 02:38:431.0.7 如果一个传感器对应物理世界中的一个小片,如何能让多个传感器对应场景中的同一个小片? 2 1.0.8 什么是图像中一个像素位置亮度的物理含义? 3 1.0.9 为什么图像常用512×512,256×256,128×128 等来表示... -
计算机应用技术(实用手册)
2011-07-29 16:32:16让默认的就可以了,但是超频玩者是肯定不会放过任何可以提高性能的东西的,所以如果你想在这里让你的电脑提升一点性能的话,就必须慢慢试验,选择一个适当的参数才能让你的计算机达到性能和稳定的最佳状态!... -
网管教程 从入门到精通软件篇.txt
2010-04-25 22:43:49Windows XP(包括 Windows 2000)的控制台命令是在系统出现一些意外情况下的一种非常有效的诊断和测试以及恢复系统功能的工具。小编的确一直都想把这方面的命令做个总结,这次辛苦老范给我们整理了这份实用的秘笈。 ... -
uboott移植实验手册及技术文档
2010-01-28 19:18:03s3c24x0: 片上系统(SOC) (5)编译 #make fs2410_config; #make 本步骤将编译 u-boot.bin文件,但此时还无法运行在FS2410开发板上。 二、修改 cpu/arm920t/start.S文件,完成 U-Boot的重定向 (1)修改中断... -
[雪鱼] 山东大肉面 - https://youtu.be/ronbyc4SWK4
2020-12-09 09:07:41和济宁的甏肉 济南的把子肉很相似 34 00:04:18,200 --> 00:04:22,520 肉一看就是肥瘦相间的 有肥有瘦的 35 00:04:24,360 --> 00:04:27,640 炖的呢 都是特别软烂 36 00:04:28,040 --> 00:04:31,040 用... -
《数据结构 1800题》
2012-12-27 16:52:036.解释和比较以下各组概念【华南师范大学 2000 一(10分)】 (1)抽象数据类型及数据类型 (2)数据结构、逻辑结构、存储结构 (3)抽象数据类型【哈尔滨工业大学 2000 一、1(3分)】 (4)算法的时间复杂性 ... -
【美食作家王刚】川味花椒鱼 - https://youtu.be/yomfziDeS1A
2020-12-09 03:57:15“花椒鱼”在做法型制上和“水煮”系列相似,但又由于不像“水煮鱼”广为人知,所以其实“花椒鱼”在配料选择和做法上就没有太多限制,一般在最后起锅之后泼上现炸花椒油的大锅炖鱼其实都可以称之...
-
BasicTraining总教程-2020.pdf
-
基于双向分布反射函数的红外偏振特性分析
-
C++MFC开发远程控制软件教程(VS2013)
-
白话:java从入门到实战
-
虚幻4引擎基础
-
衍射误差对相位校正效果的影响
-
共享图书管理系统数据库实现
-
Mycat 实现 MySQL的分库分表、读写分离、主从切换
-
url标识符作用详解
-
自定义thumb上带文本显示的拖动条Demo.zip
-
壹壹播放器2.0例子 e4a源码
-
Galera 高可用 MySQL 集群(PXC v5.6 + Ngin
-
MaxScale 实现 MySQL 读写分离与负载均衡
-
Unity ILRuntime框架设计
-
libFuzzer视频教程
-
List<Map<String,Object>> 按 key 进行分组
-
原生Ajax
-
SNOW-V-VHDL
-
DHCP 动态主机配置服务(在Linux环境下,配置单网段或跨网段提)
-
龙芯生态应用开发基础:C语言精要