Leetcode动态规划习题集
5. Longest Palindromic Substring: 最长回文子串
1) 中心扩散法:
分成奇偶由中间向两边拓展,取最长的
class Solution: def longestPalindrome(self, s: str) -> str: res = "" maxLen = 0 n = len(s) for i in range(n): # odd l,r = i,i while l>=0 and r<n and s[l]==s[r]: if maxLen < r-l+1: maxLen = r-l+1 res = s[l:l+maxLen] l -= 1 r += 1 # even l,r = i,i+1 while l>=0 and r<n and s[l]==s[r]: if maxLen < r-l+1: maxLen = r-l+1 res = s[l:l+maxLen] l -= 1 r += 1 return res
2) DP
dp[i][j] 成为的前提是 s[i]==s[j] 且 dp[i+1][j-1] 的上一个子串也是回文串
class Solution { public String longestPalindrome(String s) { int n = s.length(); String res = Character.toString(s.charAt(n-1)); boolean[][] dp = new boolean[n][n]; for(int i=n-1;i>=0;i--){ for(int j=i;j<n;j++){ // 需要当前字符相等并且向内的上一个状态相等 // j-i<3 防止溢出 dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<3 || dp[i+1][j-1]); if(dp[i][j] && (res.length()<j-i+1)) res = s.substring(i,j+1); } } return res; } }
53. Maximum Subarray: 最大子序和
直接对比当前元素和上一个状态加上当前数哪个合适
class Solution { public: int maxSubArray(vector<int>& nums) { vector<int> dp(nums.size()+1,0); dp[0] = nums[0]; int res = nums[0]; for(int i=1;i<nums.size();i++){ dp[i] = max(dp[i-1]+nums[i],nums[i]); res = max(res,dp[i]); } return res; } };
62. Unique Paths: 独一无二的路径
class Solution: def uniquePaths(self, m: int, n: int) -> int: dp = [[0]*m]*n for i in range(0,n): for j in range(0,m): if i==0 or j==0: dp[i][j] = 1 else: dp[i][j] = dp[i][j-1]+dp[i-1][j] return dp[-1][-1]
63. Unique Paths II
加了障碍,需要单独判断是不是1
class Solution: def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: n = len(obstacleGrid) m = len(obstacleGrid[0]) dp = [[0]*(m)]*(n) if obstacleGrid[0][0] == 1: return 0 if n==1: for e in obstacleGrid[0]: if e == 1: return 0 if m==1: for e in obstacleGrid: if e == 1: return 0 for i in range(0,n): for j in range(0,m): if obstacleGrid[i][j] == 0: if i==0 and j==0: dp[i][j] = 1 elif i == 0: dp[0][j] = 1 if dp[0][j - 1] == 1 else 0 elif j == 0: dp[i][0] = 1 if dp[i - 1][0] == 1 else 0 else: dp[i][j] = dp[i][j-1]+dp[i-1][j] if obstacleGrid[i][j] == 1: dp[i][j] = 0 return dp[-1][-1]
64. Minimum Path Sum
二维数组一般用二维DP,DP数组直接代表求和
class Solution: def minPathSum(self, grid: List[List[int]]) -> int: n = len(grid) m = len(grid[0]) for i in range(0,n): for j in range(0,m): if i==0 and j==0: pass elif i == 0: grid[i][j] += grid[i][j-1] elif j == 0: grid[i][j] += grid[i-1][j] else: grid[i][j] += min(grid[i][j-1],grid[i-1][j]) return grid[-1][-1]
70. Climbing chairs
斐波那契
class Solution { public: int climbStairs(int n) { if(n==1) return 1; if(n==2) return 2; int dp[n+1]; dp[0] = 1; dp[1] = 2; for(int i=2;i<n;i++){ dp[i] = dp[i-1] + dp[i-2]; } return dp[n-1]; } };
72. Edit Distance
https://blog.csdn.net/chichoxian/article/details/53944188
class Solution: def minDistance(self, word1: str, word2: str) -> int: memo = {} def dp(i,j): # 如果已经有了,直接读取 if (i,j) in memo: return memo[(i,j)] if i==-1: return j+1 if j==-1: return i+1 # 如果字母相同,延用之前的编辑数 if word1[i]==word2[j]: memo[(i,j)] = dp(i-1,j-1) else: memo[(i,j)] = min( # +1代表一次操作 dp(i,j-1)+1, # 插入 dp(i-1,j)+1, # 删除 dp(i-1,j-1)+1 # 替换 ) return memo[(i,j)] return dp(len(word1)-1,len(word2)-1)
121. Best Time to Buy and Sell Stock
常规方法
class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) res = 0 minVal = 0x7fffffff for i in range(0,n): minVal = min(minVal,prices[i]) res = max(prices[i]-minVal,res) return res
递推方程:
class Solution { public int maxProfit(int[] prices) { int n = prices.length; // dp只有两种状态 // 第一维是天数,第二维是状态:0没有股票,1有股票 int[][] dp = new int[n+1][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i=1;i<n;i++){ // 要么今天休战,要么卖掉持有的股票,才能保证没有股票 dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]); // 要么今天休战,要么只能买一次股票,才能保证持有股票 dp[i][1] = Math.max(dp[i-1][1],-prices[i]); } // 最后没有股票的状态 return dp[n-1][0]; } }
122. Best Time to Buy and Sell Stock II
无限次交易
class Solution { public int maxProfit(int[] prices) { int n = prices.length; int[][] dp = new int[n][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for (int i = 1; i < n; i++) { dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]); dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]); //可以交易多次 } return dp[n - 1][0]; } }
309. Best Time to Buy and Sell Stock with Cooldown
多了冷冻期,所以买入的时候隔了一次
class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) if n < 1: return 0 dp = [[0,0] for i in range(n)] dp[0][0] = 0 dp[0][1] = -prices[0] for i in range(1,n): dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]) dp[i][1] = max(dp[i-1][1],dp[i-2][0]-prices[i]) # i-2隔了一次 return dp[-1][0]
198. House Robber
每隔一个计算累加
class Solution: def rob(self, nums: List[int]) -> int: if not nums: return 0 n = len(nums) dp = [0]*(n+1) dp[0] = 0 dp[1] = nums[0] for i in range(1,n): dp[i+1] = max(dp[i],dp[i-1]+nums[i]) return dp[-1]
213. House Robber II
因为首位不能抢劫,所以只需要将其拆解成两个子问题即可,0->(n-2) 和 1->(n-1)
class Solution: def rob(self, nums: List[int]) -> int: if not nums: return 0 n = len(nums) dp1 = [0]*(n) dp2 = [0]*(n) if n == 1: return nums[0] nums1 = nums[0:n-1] nums2 = nums[1:n] dp1[1] = nums1[0] dp2[1] = nums2[0] for i in range(1,n-1): dp1[i+1] = max(dp1[i],dp1[i-1]+nums1[i]) dp2[i+1] = max(dp2[i],dp2[i-1]+nums2[i]) return max(max(dp1),max(dp2))
浙公网安备 33010602011771号