动态规划-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原题,用来应付算法题面试,所以开始对这些题进行" ...
随机推荐
- [reviewcode] 那些基础comments
多次提醒我,为变量取个合适的名字, so cute person: Not a big deal, but try using variable names better than my_sa 每个参 ...
- 0012 sublime快捷操作emmet语法
Emmet的前身是Zen coding,它使用缩写,来提高html/css的编写速度. 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab 键, 就可以生成 如果想要生成多个相同标签 ...
- eclipse中如何配置tomcat
1.打开eclipse上面的Windows选项,选择Preferences==>Server==>Runtime Environments==>Add 2.选择你电脑中安装的tomc ...
- maven安装与常用命令
maven安装: 下载地址http://maven.apache.org/download.cgi 1.安装好Java,配置好Java的环境变量(JDK) 2.下载apache-maven-3.5.2 ...
- 洛谷$P$2522 $Problem\ b\ [HAOI2011]$ 莫比乌斯反演
正解:莫比乌斯反演 解题报告: 传送门! 首先看到这个显然就想到莫比乌斯反演$QwQ$? 就先瞎搞下呗$QwQ$ $gcd(x,y)=k$,即$gcd(\left \lfloor \frac{x}{k ...
- JVM探秘:内存溢出
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 在 Java 虚拟机内存区域中,除了程序计数器外,其他几个内存区域都可能会发生OutO ...
- 10道java经典算法题,每一题都能帮你提升java水平!
JAVA经典算法题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: ...
- 洛谷P5664 Emiya 家今天的饭 题解 动态规划
首先来看一道题题: 安娜写宋词 题目背景 洛谷P5664 Emiya 家今天的饭[民间数据] 的简化版本. 题目描述 安娜准备去参加宋词大赛,她一共掌握 \(n\) 个 词牌名 ,并且她的宋词总共有 ...
- 1078 字符串压缩与解压 (20分)C语言
文本压缩有很多种方法,这里我们只考虑最简单的一种:把由相同字符组成的一个连续的片段用这个字符和片段中含有这个字符的个数来表示.例如 ccccc 就用 5c 来表示.如果字符没有重复,就原样输出.例如 ...
- 从头学pytorch(十四):lenet
卷积神经网络 在之前的文章里,对28 X 28的图像,我们是通过把它展开为长度为784的一维向量,然后送进全连接层,训练出一个分类模型.这样做主要有两个问题 图像在同一列邻近的像素在这个向量中可能相距 ...