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))

 

posted @ 2021-03-05 17:24  张王李代茂  阅读(94)  评论(0)    收藏  举报