动态规划-Dynamic Programming(DP)
动态规划
动态规划方法心得
动态规划是一般的面试、笔试中的高频算法题,熟练掌握必要的。动态规划的中心思想是在解决当前问题时,可以由之前已经计算所得的结果并结合现在的限制条件递推出结果。由于此前的计算结果已经保留下来,所以极大的缩短了时间复杂度。
解决动态规划问题的关键是找出状态表达式,即如何由之前的结果推导出现在的结果。另外,有的问题有很多限制条件增加问题的难度,需要剥丝抽茧,将问题解决。在找到状态表达式后,分为三步解决问题:
一. 定义内存空间,用来保存每步结果,并根据题目初始化,有些简单的题目只与前一步相关就不需要定义内存。
二. 根据状态转移表达式依次计算每步的结果,这里需要注意各种限制条件。
三. 将内存中的数据根据要求作为问题的结果返回。
动态规划题目总结
5. 最长回文子串
题目描述: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
解题思路:动态规划最重要的就是找到状态转移矩阵,此题进行二层循环遍历是否是回文字符串,首先定义一个全为False的二维数组,当前遍历的的结果取决于收尾是否相等和除去收尾的字符串是否为回文字符串两个条件,由此可得状态转移矩阵为:\(dp[l, r] = (s[l] == s[r] and (r - l <= 2 or dp[l + 1, r - 1]))\)。
代码
class Solution:
def longestPalindrome(self, s: str) -> str:
size = len(s)
if size <= 1:
return s
# 二维 dp 问题
# 状态:dp[l,r]: s[l:r] 包括 l,r ,表示的字符串是不是回文串
# 定义二维列表,并规定全部取值为False,这也是后面为什么没有输出False的原因
dp = [[False for _ in range(size)] for _ in range(size)]
longest_l = 1
res = s[0]
# 因为只有 1 个字符的情况在最开始做了判断
# 左边界一定要比右边界小,因此右边界从 1 开始
for r in range(1, size):
for l in range(r):
# 状态转移方程:如果头尾字符相等并且中间也是回文
# 在头尾字符相等的前提下,如果收缩以后不构成区间(最多只有 1 个元素),直接返回 True 即可
# 否则要继续看收缩以后的区间的回文性
# 重点理解 or 的短路性质在这里的作用
if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
dp[l][r] = True
cur_len = r - l + 1
if cur_len > longest_l:
longest_l = cur_len
res = s[l:r + 1]
return res
10. 正则表达式匹配
32. 最长有效括号
44. 通配符匹配
53. 最大子序和
题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
解题思路:思路一:首先,使用第一个数初始化最大连续数组和;然后遍历数组,并依次相加;当超过之前的最大值时就替换,当小于0时就重新初始化为0。思路二:动态规划。遍历数组,状态转移矩阵为:dp[i] = dp[i-1] + dp[i],不过如思路一相同,当前面连续和大于0时就继续加上当前的值,当小于0时就重新计算。此题由于只与前一结果关就没有单独定义列表去储存结果。
思路一:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_val, cur = nums[0], 0
for x in nums:
cur += x
if cur > max_val:
max_val = cur
if cur < 0:
cur = 0
return max_val
思路二:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
max_sum = nums[0]
for i in range(1, n):
if nums[i - 1] > 0:
nums[i] += nums[i - 1]
max_sum = max(nums[i], max_sum)
return max_sum
62. 不同路径
题目描述:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?
解题思路:典型的动态规划题目,首先创建存放结果的列表,然后依次由已知的第一行和第一列循环计算,状态转移矩阵为:dp[i, j] = dp[i-1, j] + dp[i, j-1],最后输出d[-1, -1]。
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 动态规划
# 定义二维空列表
dp = [[0 for i in range (n+1)] for i in range(m+1)]
# 初始化第一行列表的值
for i in range(1, n+1):
dp[1][i] = 1
# 由状态转移矩阵求解列表其余的值
for i in range(2, m+1):
for j in range(1, n+1):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
# 返回最后的值
return dp[m][n]
63. 不同路径II
题目描述:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
解题思路:与上题的解题思路相同,不同的是当遇到障碍物时,列表的值不是由状态转移矩阵计算而来,而是直接设为0。
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
# 同样是动态规划,不过在障碍处标记为0,并且不进行遍历;
m, n = len(obstacleGrid), len(obstacleGrid[0])
dp = [[0 for i in range(n+1)] for j in range(m+1)]
for i in range(1, n+1):
if obstacleGrid[0][i-1] == 1:
break
else:
dp[1][i] = 1
for i in range(2,m+1):
for j in range(1,n+1):
if obstacleGrid[i-1][j-1]:
dp[i][j] = 0
else:
dp[i][j]=dp[i-1][j]+dp[i][j-1]
return dp[m][n]
64. 最小路径和
题目描述:给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步
解题思路:典型动态规划题,老套路,定义二维列表,初始化第一行和第一列的值,遍历列表,根据状态转移矩阵dp[i, j] = min(dp[i, j-1], dp[i-1, j]) + grid[i, j]
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m , n = len(grid) , len(grid[0])
dp = [[0x7fffffff for x in range(n+1)] for x in range(m+1)]
dp[0][1] = dp[1][0] = 0
for i in range(1,m+1):
for j in range(1,n+1):
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i-1][j-1]
return dp[m][n]
70. 爬楼梯
题目描述:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
解题思路:典型动态规划问题,状态转移矩阵:dp[i] =dp[i-1] + dp[i-2]。于此相同的就是斐波那契数列。
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
elif n == 2:
return 2
else:
a, b =1, 2
for i in range(n-2):
c = a + b
a = b
b = c
return c
91. 解码方法
题目描述: 一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
解题思路:此题和爬楼梯问题类似,不一样的是增加了很多限制条件。(1)最后两位数是否可以解码,也就是是否在1~26之间;(2)只对最后一位进行解码时,最后一位数是否为0;
class Solution:
def numDecodings(self, s: str) -> int:
if not s: return 0
n = len(s)
dp = [0] * n
dp[0] = 1 if s[0] != '0' else 0
for i in range(1, n):
if 10 <= int(s[i - 1:i + 1]) <= 26:
dp[i] += dp[i - 2] if i >= 2 else 1
if s[i] != '0':
dp[i] += dp[i - 1]
return dp[n - 1]
120. 三角形最小路径和
题目描述:给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
解题思路:
说明:如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
mini, M = triangle[-1], len(triangle)
for i in range(M - 2, -1, -1):
for j in range(len(triangle[i])):
mini[j] = triangle[i][j] + min(mini[j], mini[j+1])
return mini[0]
动态规划-Dynamic Programming(DP)的更多相关文章
- 动态规划(Dynamic Programming, DP)---- 最大连续子序列和
动态规划(Dynamic Programming, DP)是一种用来解决一类最优化问题的算法思想,简单来使,动态规划是将一个复杂的问题分解成若干个子问题,或者说若干个阶段,下一个阶段通过上一个阶段的结 ...
- 动态规划Dynamic Programming
动态规划Dynamic Programming code教你做人:DP其实不算是一种算法,而是一种思想/思路,分阶段决策的思路 理解动态规划: 递归与动态规划的联系与区别 -> 记忆化搜索 -& ...
- 6专题总结-动态规划dynamic programming
专题6--动态规划 1.动态规划基础知识 什么情况下可能是动态规划?满足下面三个条件之一:1. Maximum/Minimum -- 最大最小,最长,最短:写程序一般有max/min.2. Yes/N ...
- 动态规划(Dynamic Programming)算法与LC实例的理解
动态规划(Dynamic Programming)算法与LC实例的理解 希望通过写下来自己学习历程的方式帮助自己加深对知识的理解,也帮助其他人更好地学习,少走弯路.也欢迎大家来给我的Github的Le ...
- 动态规划 Dynamic Programming 学习笔记
文章以 CC-BY-SA 方式共享,此说明高于本站内其他说明. 本文尚未完工,但内容足够丰富,故提前发布. 内容包含大量 \(\LaTeX\) 公式,渲染可能需要一些时间,请耐心等待渲染(约 5s). ...
- 动态规划 Dynamic Programming
March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...
- 最优化问题 Optimization Problems & 动态规划 Dynamic Programming
2018-01-12 22:50:06 一.优化问题 优化问题用数学的角度来分析就是去求一个函数或者说方程的极大值或者极小值,通常这种优化问题是有约束条件的,所以也被称为约束优化问题. 约束优化问题( ...
- 动态规划系列(零)—— 动态规划(Dynamic Programming)总结
动态规划三要素:重叠⼦问题.最优⼦结构.状态转移⽅程. 动态规划的三个需要明确的点就是「状态」「选择」和「base case」,对应着回溯算法中走过的「路径」,当前的「选择列表」和「结束条件」. 某种 ...
- Python算法之动态规划(Dynamic Programming)解析:二维矩阵中的醉汉(魔改版leetcode出界的路径数)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_168 现在很多互联网企业学聪明了,知道应聘者有目的性的刷Leetcode原题,用来应付算法题面试,所以开始对这些题进行" ...
随机推荐
- windows下Qt编译Qtxlsx库和qtxlsx库的使用方法
最近接了个项目,合作的学长让用Qt写,而其中最重要的需求是将数据库的数据写入excel表格中和将excel的数据导入到数据库中,自己查阅了和多资料,最后决定使用qtxlsx开源库来操作excel,在编 ...
- python multiprocessing.freeze_support
Running on windows platform, give me an error as below: File "C:\Python\lib\multiprocessing\for ...
- Java中的变量、数据类型和运算符
1. java语言是一种强类型的语言,对各种数据类型都有明确的区分,而计算机使用内存来记忆大量运算时需要使用的数据,而当声明一个变量时,即在内存中划分一块空间存储数据,而变量类型决定划分内存空间的大小 ...
- resin部署安装
Resin是CAUCHO公司的产品,是一个非常流行的application server,对servlet和JSP提供了良好的支持,性能也比较优良,resin自身也是采用JAVA语法开发,功能近似于t ...
- 如何利用腾讯云COS为静态博客添加动态相册
前言 本文首发于个人网站Jianger's Blog,欢迎访问订阅.个人博客小站刚建站不久,想着除了主题里的功能外再添加上相册模块,于是半搜索半摸索把相册模块搞出来了,最后采用了利用腾讯云对象存储作图 ...
- java编程思想札记一
1. 访问权限中尤其注意protected,它包含了包访问权限,只要是同一个包里的,就能访问到protected成员. 2. 后期绑定:被调用代码直到执行时才能确定,编译阶段只保证调用方法存在和类 ...
- GNE: 4行代码实现新闻类网站通用爬虫
GNE(GeneralNewsExtractor)是一个通用新闻网站正文抽取模块,输入一篇新闻网页的 HTML, 输出正文内容.标题.作者.发布时间.正文中的图片地址和正文所在的标签源代码.GNE在提 ...
- 【题解】Leyni,罗莉和队列(树状数组)
[题解]Leyni,罗莉和队列(树状数组) HRBUST - 1356 将整个序列reverse一下,现在就变成了从高到低的排队.题目就变成了,定位一个妹子,问这个妹子前面的比这个妹子小的妹子中,下标 ...
- iOS获取网络数据/路径中的文件名
NSString * urlString = @"http://www.baidu.com/img/baidu_logo_fqj_10.gif"; //方法一:最直接 NSStri ...
- 1061 判断题 (15 分)C语言
判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分. 输入格式: 输入在第一行给出两个不超过 100 的正整数 N 和 M,分别是学生人数和判断题数量.第二行给出 M ...