DP(Dynamic Programming)动态规划

动态规划(英语:Dynamic programming,简称 DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。动态规划往往用于优化递归问题,例如斐波那契数列,如果运用递归的方式来求解会重复计算很多相同的子问题,利用动态规划的思想可以减少计算量。

通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,具有天然剪枝的功能,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

链接:https://leetcode-cn.com/tag/dynamic-programming/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


学习动态规划,这是一种解决棘手问题的方法,它将问题分解成小问题,并先着手解决这些小问题。
每个动态规划算法都从一个网格开始
动态规划可以帮助在给定约束条件下找到最优解
在这里插入图片描述
一个问题如果要用动态规划解的话,需要考虑下面的几个点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

背包问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

旅游行程最优化

在这里插入图片描述
在这里插入图片描述

最长公共子串

在这里插入图片描述

疑问:如果答案不在最后一个格子的话,该怎么取值?

最长公共子序列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.最长回文子串

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//java    通过了
class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        int n = s.length();
        boolean[][] dp = new boolean[n][n];

        for(int i = n; i >= 0; i--){
            for(int j = i; j < n; j++){
                if(j == i || j == i+1){
                    dp[i][j] = (s.charAt(i) == s.charAt(j));
                }else{
                    dp[i][j] = (dp[i+1][j-1] && s.charAt(i) == s.charAt(j));
                }

                if(dp[i][j] && (j-i+1 > res.length())){
                    res = s.substring(i, j+1);
                }
            }
        }
        return res;
    }
}
/*
输入:"babad"
i\j  0  1  2  3  4
0	 1  0  1  0  0
1    0  1  0  1  0
2    0  0  1  0  0
3	 0  0  0  1  0
4	 0  0  0  0  1
*/
#和上面的java思路一样 但是一直超出时间限制
class Solution:
    def longestPalindrome(self, s: str) -> str:
        res = ""          #最长回文子串
        a=[[False for _ in range(len(s))]for _ in range(len(s))]  #生成二维数组并初始化

        for i in range(len(s)-1, -1, -1): #长度为5的话,输出:4,3,2,1,0           
            for j in range(i, len(s)):
                #print(i, j)
                if(j == i or j == i+1):
                    a[i][j] = (s[i] == s[j])
                else:
                    a[i][j] = (a[i+1][j-1] == 1 and s[i] == s[j])

                if(a[i][j] and (j-i+1 > len(res))):
                    res = s[i:j+1]

        return res

动态规划 空间优化
在这里插入图片描述

//java
class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        int n = s.length();
        boolean[] dp = new boolean[n];

        for(int i = n-1; i >= 0; i--){
            for(int j = n-1; j >= i; j--){
                if(j == i || j == i+1){
                    dp[j] = (s.charAt(i) == s.charAt(j));
                }else{
                    dp[j] = (dp[j-1] && s.charAt(i) == s.charAt(j));
                }

                if(dp[j] && (j-i+1 > res.length())){
                    res = s.substring(i, j+1);
                }
            }
        }
        return res;
    }
}

62.不同路径

在这里插入图片描述
在这里插入图片描述

//java  anan  2020.3.2
class Solution {
    public int uniquePaths(int m, int n) {
        int dp[][] = new int[n][m];
        dp[0][0] = 1;

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(i > 0 || j > 0){  //设置条件是为了除去初值
                    dp[i][j] = (i-1>=0 ? dp[i-1][j] : 0) + (j-1>=0 ? dp[i][j-1] : 0);
                }
            }
        }

        return dp[n-1][m-1];
    }
}

63.不同路径 II

在这里插入图片描述
在这里插入图片描述

//java    anan  2020.3.2
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;

        if(obstacleGrid[n-1][m-1] == 1){  //[[0,1]]
            return 0;
        }

        int dp[][] = new int[n][m];
        dp[0][0] = (obstacleGrid[0][0] == 0) ? 1:0;  //[[0]]    [[1]]

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(i > 0 || j > 0){  //设置条件是为了除去初值
                    dp[i][j] = (i-1>=0 && obstacleGrid[i-1][j]==0 ? dp[i-1][j] : 0) + (j-1>=0  && obstacleGrid[i][j-1]==0? dp[i][j-1] : 0);    //加了一些判定条件
                }
            }
        }

        return dp[n-1][m-1];
    }
}

64.最小路径和

在这里插入图片描述

//java  anan 2020.3.2
class Solution {
    public int minPathSum(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;

        int[][] dp = new int[n][m];   //dp中存的是到当前位置的最短路径
        dp[0][0] = grid[0][0];

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(i > 0 || j > 0){
                    dp[i][j] = Math.min((i-1>=0? dp[i-1][j] : Integer.MAX_VALUE), (j-1>=0? dp[i][j-1] : Integer.MAX_VALUE)) + grid[i][j];
                }
            }
        }
        return dp[n-1][m-1];
    }
}

空间优化,用一维数组

//java  anan 2020.3.2
class Solution {
    public int minPathSum(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;

        int[] dp = new int[m];   //dp中存的是到当前位置的最短路径
        dp[0] = grid[0][0];

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(i > 0 || j > 0){
                    dp[j] = Math.min((i-1>=0? dp[j] : Integer.MAX_VALUE), (j-1>=0? dp[j-1] : Integer.MAX_VALUE)) + grid[i][j];
                }
            }
        }
        return dp[m-1];
    }
}

53.最大子序和

在这里插入图片描述

//java
class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        int max = nums[0];

        dp[0] = nums[0];
        for(int i = 1; i < n; i++){
            if(dp[i-1] < 0){
                dp[i] = nums[i];
            }else{
                dp[i] = dp[i-1]+nums[i];
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}

70.爬楼梯

在这里插入图片描述

//C
int climbStairs(int n){
/*
f(1) = 1
f(2) = 2
f(3) = f(1)+ f(2)
f(4) = f(2) + f(3)
f(n) = f(n-2) + f(n-1)
*/

    int num[n+1];

    for(int i = 0; i < n+1; i++){
        if(i <= 2){
            num[i] = i;
        }else{
            num[i] = num[i-1]+num[i-2];
        }
        printf("%d ", num[i]);
    }

    return num[n];
}
//C  代码优化
int climbStairs(int n){
    int num[n+1];

    for(int i = 0; i < n+1; i++){
        num[i] = (i <= 2) ? i : num[i-1]+num[i-2];
    }

    return num[n];
}

139.单词拆分

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

#python  anan 根据题解思想写的

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        n = len(s)
        dp = [False for _ in range(n+1)]  #dp[i]表示s[0:i]可以由字典中的词构成
        dp[0] = True

        for i in range(n):
            for j in range(i+1, n+1):              
                if(s[i:j] in wordDict and (dp[i])):
                    dp[j] = True
                #print(i, j, s[i:j], dp)
        return dp[-1]
//java
public class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordDictSet=new HashSet(wordDict);
        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
}

作者:LeetCode
链接:https://leetcode-cn.com/problems/word-break/solution/dan-ci-chai-fen-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

91.解码方法

在这里插入图片描述

#python anan 2020.3.2
class Solution:
    def numDecodings(self, s: str) -> int:
        n = len(s)
        dp = [1 for _ in range(n+1)]
        
        for i in range(1,n+1):
            dp[i] = (dp[i-1] if (i >= 1 and 0 < int(s[i-1]) <= 26) else 0)  + (dp[i-2] if (i >= 2 and 0 < int(s[i-2:i]) <= 26 and int(s[i-2])!=0) else 0)
            # 加上int(s[i-2])!=0   是因为:"01"
        #print(dp)
        dp[0] = 0  #   ""空串时结果应该是0,上面设置成1是为了好迭代

        return dp[-1]

96.不同的二叉搜索树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#python
class Solution {
    public int numTrees(int n) {
        int[] dp = new int[n+1];
        dp[0] = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= i; j++){
                dp[i] += dp[j-1]*dp[i-j];
            }
        }

        return dp[n];
    }
}

322.零钱兑换

官方解答
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

//java 2020.3.9   自己结合官解思路自己写的
class Solution {
    public int coinChange(int[] coins, int amount) {
        if(amount == 0){   //特殊例子:  [1]   0
            return 0;
        }

        int[] dp = new int[amount+1];
        int min;
        Arrays.sort(coins);   //在原数组上进行排序
        Arrays.fill(dp, amount+1);
        dp[0] = 0;

        for(int i = 1; i < amount+1; i++){
            for(int j = 0; j < coins.length; j++){
                if(i-coins[j] >= 0){
                    dp[i] = Math.min(dp[i], dp[i-coins[j]]+1);
                }      
            }      
        }

        // for(int d: dp){
        //     System.out.print(d + " ");
        // }

        return dp[amount]!=amount+1 ? dp[amount] : -1;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安安csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值