coding notes leetcode-DynamicProgramming Tony Cao 2024-02-09 2024-10-29 动态规划和贪心算法 贪心算法 使用局部最优,推出全局最优算法
分发饼干
用最少数量的箭引爆气球
动态规划 基础套路
1.dp数组的定义和下标。【非常重要】
2.递推公式。
3.dp数组如何初始化,初始化也需要注意。【从哪里初始化,初始化后该如何使用,这要参考dp数组的定义】
4.遍历顺序,比较考究,01 先遍历背包,后遍历物品。
4.1排列和组合的遍历顺序是不相同的。
4.1.1 排列:背包在外 物品在内。(322)
4.1.2 组合:物品在外,背包在内。(518)
5.(出现问题)打印dp数组。(打印dp数组,检查是否有问题,检验1 2 3 4 步骤)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def dp (状态1 , 状态2 , ... ): for 选择 in 所有可能的选择: result = 求最值(result, dp(状态1 , 状态2 , ...)) return result dp[0 ][0 ][...] = base case for 状态1 in 状态1 的所有取值: for 状态2 in 状态2 的所有取值: for ... dp[状态1 ][状态2 ][...] = 求最值(选择1 ,选择2. ..)
带有备忘录的动规划(优化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def fib (N: int ) -> int : memo = [0 ] * (N + 1 ) return dp(memo, N) def dp (memo: List [int ], n: int ) -> int : if n == 0 or n == 1 : return n if memo[n] != 0 : return memo[n] memo[n] = dp(memo, n - 1 ) + dp(memo, n - 2 ) return memo[n]
初级题目 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution : def climbStairs (self, n: int ) -> int : if n <= 1 : return n dp = [0 ] * (n + 1 ) dp[1 ] = 1 dp[2 ] = 2 for i in range (3 , n + 1 ): dp[i] = dp[i - 1 ] + dp[i - 2 ] return dp[n]
最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution : def maxSubArray (self, nums: List [int ] ) -> int : size = len (nums) if size == 0 : return 0 dp = [0 for _ in range (size)] dp[0 ] = nums[0 ] for i in range (1 , size): if dp[i - 1 ] >= 0 : dp[i] = dp[i - 1 ] + nums[i] else : dp[i] = nums[i] return max (dp)
不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution : def uniquePaths (self, m: int , n: int ) -> int : """ initialize dp[i][j] in top, in left we have only 1 path dp[i][j] = the step to reach [i,j] dp[i][j] = dp[i-1][j] move right + dp[i][j-1] move bottom """ dp = [[0 for i in range (n)] for j in range (m)] for j in range (m): dp[j][0 ] = 1 for i in range (n): dp[0 ][i] = 1 for i in range (1 ,m): for j in range (1 , n): dp[i][j] = dp[i-1 ][j] + dp[i][j-1 ] return dp[-1 ][-1 ]
中级题目 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。 例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution : def lengthOfLIS (self, nums: List [int ] ) -> int : if len (nums) <= 1 : return len (nums) dp = [1 ] * len (nums) result = 0 for i in range (1 , len (nums)): for j in range (0 ,i): if nums[i] > nums[j]: dp[i] = max (dp[i], dp[j] + 1 ) result = max (result, dp[i]) return result
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution : def minDistance (self, word1: str , word2: str ) -> int : n1 = len (word1) n2 = len (word2) dp = [[0 ] * (n2 + 1 ) for _ in range (n1 + 1 )] for j in range (1 , n2 + 1 ): dp[0 ][j] = dp[0 ][j-1 ] + 1 for i in range (1 , n1 + 1 ): dp[i][0 ] = dp[i-1 ][0 ] + 1 for i in range (1 , n1 + 1 ): for j in range (1 , n2 + 1 ): if word1[i-1 ] == word2[j-1 ]: dp[i][j] = dp[i-1 ][j-1 ] else : dp[i][j] = min (dp[i][j-1 ], dp[i-1 ][j], dp[i-1 ][j-1 ] ) + 1 return dp[-1 ][-1 ]
最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:一个机器人每次只能向下或者向右移动一步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution : def minPathSum (self, grid: List [List [int ]] ) -> int : m,n = len (grid), len (grid[0 ]) dp = [[0 for _ in range (n)] for _ in range (m)] res = 0 for i in range (m): res += grid[i][0 ] dp[i][0 ] = res res = 0 for j in range (n): res += grid[0 ][j] dp[0 ][j] = res for i in range (1 ,m): for j in range (1 ,n): dp[i][j] = min (dp[i-1 ][j] + grid[i][j], dp[i][j-1 ] + grid[i][j]) return dp[-1 ][-1 ]
高级题目