动态规划的简单理解及例子

    动态规划是分治的延伸,通俗一点来说就是大事化小,小事化无的艺术,在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接使用这些结果。

1、动态规划具备了以下三个特点:

(1)把原来的问题分解为几个相似的子问题

(2)所有的子问题都只需要解决一次

(3)储存子问题的解

2、动态规划的本质就是对问题状态的定义和状态转移方程的定义(状态以及状态之间的递推关系)

3、动态规划问题一般从以下四个角度考虑:

(1)状态定义(定义的状态一定要形成递推关系)

(2)状态间的转移方程定义

(3)状态的初始化

(4)返回结果

4、使用场景:最大值/最小值,可不可行,是不是,方案个数

5、通过以下例题加深理解:

(1)

状态F(i):第i项的值

状态转移方程:F(i)= F(i-1)+ F(i-2) 

初始状态:F(0)= 0 , F(1)= 1

返回结果:F(n)

程序如下:

class Solution {
    public int fib(int n) {
        if(n < 2) return n;
        final int MOD = 1000000007;
        int p = 0,q = 0,r = 1;
        for(int i = 2;i <= n;i++){
            p = q;
            q = r;
            r = (p + q) % MOD;
        }
        return r;
        }
}

(2)

状态F(i):字符串前i个字符是否可以被分割

状态转移方程:F(i):j < i && F(j) && [j+1,i]是否可以在词典中找到

初始状态:F(0):true 辅助状态

返回结果:F(字符串长度):f(s.size) f(s.length())

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        boolean[] canBreak = new boolean[s.length() + 1];
        canBreak[0] = true;
        for(int i = 1;i <= s.length();i++){
            for(int j = 0;j < i;j++){
                if(canBreak[j] && wordDict.contains(s.substring(j,i))){
                    canBreak[i] = true;
                    break;
                }
            }
        } 
        return canBreak[s.length()];
    }
}

(3)

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] f = new int[m][n];
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(j == 0){
                    f[i][0] = 1;
                }else if(i == 0){
                    f[0][j] = 1;
                }else{
                    f[i][j] = f[i][j-1] + f[i-1][j];
                }
            }
        }
        return f[m-1][n-1];
    }
}

(4)

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        if (triangle.isEmpty()) return 0;
        int row = triangle.size();
        int[][] f = new int[row][row];
        f[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < row; i++) {
            f[i][0] = f[i - 1][0] + triangle.get(i).get(0);
            for (int j = 1; j <i; j++) {
                f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j);
            }
            f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);
            }     
        int minSum = f[row-1][0];
        for(int j = 1; j < row; j++) {
            minSum = Math.min(minSum, f[row-1][j]);
        }
        return minSum;
    }
}

(5)

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] f = new int[m][n];
        f[0][0] = grid[0][0];
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){ 
                if(j == 0 && i != 0){
                    f[i][0] = f[i-1][0] + grid[i][0];
                }else if(j != 0 && i == 0){
                    f[0][j] = f[0][j-1] + grid[0][j];
                }else if(j != 0 && i != 0){
                     f[i][j] = Math.min(f[i-1][j],f[i][j-1]) + grid[i][j];
                }
            }
        }
        return f[m-1][n-1];
    }
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

薰衣草2333

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

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

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

打赏作者

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

抵扣说明:

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

余额充值