0
点赞
收藏
分享

微信扫一扫

动态规划的一些练习题(上)

Villagers 2022-02-21 阅读 31

1. 零钱兑换

题目

class Solution {
    public int coinChange(int[] coins, int amount) {
        int n = coins.length;
        int[] arr = new int[amount + 1];// 0..amount

        // 定义初始条件
        arr[0] = 0;
        for(int i = 1; i <= amount; i++) {
            // 求arr[i]
            arr[i] = Integer.MAX_VALUE;
            for(int j = 0; j < n; j++) {
                if(i >= coins[j] && arr[i - coins[j]] != Integer.MAX_VALUE && arr[i - coins[j]] + 1 < arr[i]) {
                    arr[i] = arr[i - coins[j]] + 1;
                }

            }
        }
        if (arr[amount] == Integer.MAX_VALUE) {
            return -1;
        }else {
            return arr[amount];
        }
        

    }
}

2. 不同路径-1

题目

分析:

动态规划第一步:确定状态

a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]

动态规划第二步:状态转移方程

f[i][j] = f[i - 1][j] + f[i][j - 1]

动态规划第三步:初始条件和边界条件

初始条件:f[0][0] = 1
边界条件:i = 0或者j = 0的时候,只能从一个方向过来f[0][j] =1 f[i][0] = 1

动态规划第四步:计算顺序

计算第0行
计算第1行
。。。
计算第m - 1行
答案就是f[m - 1][n -1]

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

3. 不同路径-2

题目

分析:这个题和1的区别在于 障碍的地方f[i][j] = 0,然后就是边界条件中在最上边和最左边不再是直接等于1了,而是由它前面一个来决定!

动态规划第一步:确定状态

a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]

动态规划第二步:状态转移方程

f[i][j] = f[i - 1][j] + f[i][j - 1]

动态规划第三步:初始条件和边界条件

初始条件:f[0][0] = 1
边界条件:i = 0或者 j = 0, f[i][j] = f[i ][j - 1]或者f[i - 1][j]

动态规划第四步:计算顺序

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][] arr = new int[m][n];
        if(obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
            return 0;
        }else{
            arr[0][0] = 1;
            for(int i = 0; i < m; i++) {
                for(int j = 0; j < n; j++) {
                    if(obstacleGrid[i][j] == 1) {
                        arr[i][j] = 0;
                    }else{
                        if(i == 0 && j == 0){
                            arr[i][j] = 1;
                        }else{
                            if(i == 0) {
                                arr[i][j] = arr[i][j - 1];
                            }
                            if(j == 0) {
                                arr[i][j] = arr[i - 1][j];
                            }
                            if(i != 0 && j != 0) {
                                arr[i][j] = arr[i - 1][j]+ arr[i][j - 1];
                            }
                        }
                    }
                }
            }
        }

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

4. 跳跃游戏

题目

分析:

动态规划第一步:确定状态

a. 最后一步: 无论怎么样到最后一步,都是前面的某一步直接跳过去的
b. 子问题,能成功跳到最后一步j位置是上一次跳成功了在i位置,并且i位置能跳的步数能够到j

动态规划第二步:状态转移方程

f[j] = or{i = 0到j-1}{f[i] && nums[i] > j - i}

动态规划第三步:初始条件和边界条件

初始条件:f[0]= true
边界条件:无

动态规划第四步:计算顺序

从小到大依次计算。

class Solution {
    public boolean canJump(int[] nums) {
        // f[j]是true的条件有两个
        // 1. f[i] = true 2. nums[i] > j - i
        if (nums == null || nums.length == 0) return false;
        int n = nums.length;
        boolean[] arr = new boolean[n+1];
        arr[0] = true;
        

        for(int i = 1; i < n; i++) {
            
            arr[i] = false; // 这儿是个小细节
            for(int j = 0; j < i; j++) {
                if(arr[j] && nums[j] >= i - j) {
                    arr[i] = true;
                    break;
                }
            }
           
        }
        return arr[n - 1];
    }
}

5. 粉刷房子

粉刷房子2请移步12题
题目
分析:
序列型动态规划:前i个最小/方式数/最小
序列➕状态

class Solution {
    public int minCost(int[][] costs) {
        int n = costs.length;// 房子的个数
        int[][] arr = new int[3][n];
        //arr[0][i] 代表第i栋房子是红色时,前i栋房子的最低价
        // arr[1][i] 代表第i栋房子是蓝色时,前i栋房子的最低价
        // arr[2][i] 代表第i栋房子是绿色时,前i栋房子的最低价

        // 初始条件
        for(int i = 0; i < 3; i++) {
            arr[i][0] = costs[0][i];
        }
        for(int i = 1; i < n; i ++) {
            arr[0][i] = arr[1][i - 1] > arr[2][i - 1] ? arr[2][i - 1] + costs[i][0]: arr[1][i - 1] + costs[i][0];
            arr[1][i] = arr[0][i - 1] > arr[2][i - 1] ? arr[2][i - 1] + costs[i][1]: arr[0][i - 1] + costs[i][1];
            arr[2][i] = arr[0][i - 1] > arr[1][i - 1] ? arr[1][i - 1] + costs[i][2]: arr[0][i - 1] + costs[i][2];
        }
        return getMin(arr[0][n - 1], arr[1][n - 1], arr[2][n - 1]);

        
    }
    public int getMin(int a, int b, int c) {
        int temp = a>b?b:a;
        return temp>c?c:temp;
    }

}

6. 解码方法

题目

我的解法,非常啰嗦

class Solution {
    public int numDecodings(String s) {
        if(s == null || s.charAt(0) == '0') {
            return 0;
        }else if(s.length() == 1 && s.charAt(0) != '0' ) {
            return 1;
        }else{
            int n = s.length();
            int[] arr = new int[n];
            arr[0] = 1;
           
            if(s.charAt(0) == '1' && s.charAt(1) != '0') {
                    // 如果第一位是1或者2的话
                    arr[1] = 2;
                }else if(s.charAt(0) == '2'&& Character.getNumericValue(s.charAt(1)) <= 6 && s.charAt(1) != '0') {
                   arr[1] = 2; 
                }else if(Character.getNumericValue(s.charAt(0))>= 3&& s.charAt(1) == '0') {
                    // arr[1] = 0;
                    return 0;
                }else if(s.charAt(0) == '0'&& s.charAt(1) == '0') {
                    return 0;
                }
                else{
                    arr[1] = 1;
                }
            for(int i = 2; i < n; i++){
                if(s.charAt(i - 1) == '1' && s.charAt(i) != '0') {
                    // 如果第一位是1或者2的话
                    arr[i] = arr[i - 1] + arr[i - 2];
                }else if(Character.getNumericValue(s.charAt(i - 1))>= 3 && s.charAt(i) == '0') {
                    // arr[1] = 0;
                    return 0;
                }else if(s.charAt(i - 1) == '0' && s.charAt(i) == '0') {
                    return 0;
                }
                else if(s.charAt(i - 1) == '2' && Character.getNumericValue(s.charAt(i)) <= 6 && s.charAt(i) != '0') {
                   arr[i] = arr[i - 1] + arr[i - 2];
                }else if(s.charAt(i - 1) == '1' && s.charAt(i) == '0'){
                   arr[i] = arr[i - 2];
                }else if (s.charAt(i - 1) == '2' && s.charAt(i) == '0'){
                    arr[i] = arr[i - 2];
                }else{
                    arr[i] = arr[i - 1];
                }
            }

            return arr[n - 1];
        }
            
        
    }
}

一个比较简洁并且具有技巧性的解法

class Solution {
    public int numDecodings(String s) {
        char[] ss = s.toCharArray();
        int n = ss.length;
        if (n == 0) {
            return 0;
        }
        int[] arr = new int[n+1];
        int m = ss[0] - '0';
        arr[0] = 1;
        for(int i = 1; i <= n; i++) {
            arr[i] = 0;
            int t = ss[i - 1] - '0';
            if(t >= 1 && t <= 9){
                arr[i] += arr[i - 1];
            }
            if(i >= 2) {
                int q = ss[i - 2] - '0';
                int p = ss[i - 1] - '0';
                if(q * 10 + p >= 10 && q * 10 + p <= 26) {
                    arr[i] += arr[i - 2];// 学好加等
                }
            }
            
            
        }
        return arr[n];
        
    }
}

7. 最长连续递增子序列

坐标型动态规划
题目

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int n = nums.length;
        if(n == 0) {
            return 0;
        }else{
            int[] arr = new int[n];
            arr[0] = 1;
            int m = 1;
            for(int i = 1;i < n; i++) {
                if(nums[i]> nums[i - 1]){
                    arr[i] = arr[i - 1] + 1;
                }else{
                    arr[i] = 1;
                }
                if(m <= arr[i]){
                    m = arr[i];
                }
            }
            return m;
        }
        

    }
}

8. 最小路径和

题目

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] arr = new int[m][n];
        arr[0][0] = grid[0][0];
        for(int i = 1; i < m; i++) {
            arr[i][0] = arr[i - 1][0] + grid[i][0];
        }
        for(int i = 1; i < n; i++) {
            arr[0][i] = arr[0][i - 1] + grid[0][i];
        }

        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                arr[i][j] = arr[i - 1][j] < arr[i][j - 1] ? grid[i][j] + arr[i - 1][j]: grid[i][j] + arr[i][j - 1];
            }
        }
        return arr[m - 1][n - 1];

    }
}

9. 轰炸敌人

题目

public static int maxKillEnemies(char[][] A) {
    if (A == null || A.length == 0 || A[0].length == 0) {
      return 0;
    }
    int m = A.length;
    int n = A[0].length;

    int[][] f = new int[m][n];
    int[][] res = new int[m][n];

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        res[i][j] = 0;
      }
    }

    // up
    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        if (A[i][j] == 'W') {
          f[i][j] = 0;
        }else {
          f[i][j] = 0;
          if (A[i][j] == 'E') {
            f[i][j] = 1;
          }
          if (i > 0) {
            f[i][j] += f[i - 1][j];
          }
        }
        res[i][j] += f[i][j];
      }
    }

    // down
    for (int i = m - 1; i >= 0; i--) {
      for (int j = n - 1; j >= 0; j--) {
        if (A[i][j] == 'W') {
          f[i][j] = 0;
        }else {
          f[i][j] = 0;
          if (A[i][j] == 'E') {
            f[i][j] = 1;
          }
          if (i < m - 1) {
            f[i][j] += f[i + 1][j];
          }
        }
        res[i][j] += f[i][j];
      }
    }

    // left
    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        if (A[i][j] == 'W') {
          f[i][j] = 0;
        }else {
          f[i][j] = 0;
          if (A[i][j] == 'E') {
            f[i][j] = 1;
          }
          if (j > 0) {
            f[i][j] += f[i][j - 1];
          }
        }
        res[i][j] += f[i][j];
      }
    }

    // right
    for (int i = 0; i < m; i++) {
      for (int j = n - 1; j >= 0; j--) {
        if (A[i][j] == 'W') {
          f[i][j] = 0;
        }else {
          f[i][j] = 0;
          if (A[i][j] == 'E') {
            f[i][j] = 1;
          }
          if (j < n - 1) {
            f[i][j] += f[i][j + 1];
          }
        }
        res[i][j] += f[i][j];
      }
    }
    int result = Integer.MIN_VALUE;

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        if (A[i][j] == '0') {
          result = result > res[i][j] ? result:res[i][j];
        }
      }

    }

    return result;
  }

10.杨辉三角形

题目

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> dp = new ArrayList<List<Integer>>();
        List<Integer> tmp = new ArrayList<Integer>();
        tmp.add(1);
        dp.add(tmp);
        if(numRows == 1) {
            return dp;
        }
        List<Integer> tmp2 = new ArrayList<Integer>();
            tmp2.add(1);
            tmp2.add(1);
            dp.add(tmp2);
        if(numRows == 2) {
            return dp;
        }
        

        for(int i = 2; i < numRows; i++) {
            List<Integer> t = new ArrayList<Integer>();
            t.add(1);
            for(int j = 1; j < i; j++) {
                t.add(dp.get(i - 1).get(j - 1) + dp.get(i - 1).get(j));
            }
            t.add(1);
            dp.add(t);
        }
        return dp;
    }
}

11. 比特位计数

题目

class Solution {
    public int[] countBits(int n) {
        if(n == 0) {
            return new int[]{0};
        }else{
            int[] dp = new int[n + 1];
            dp[0] = 0;
            dp[1] = 1;
            for(int i = 2; i <= n; i++) {
                dp[i] = dp[i >> 1] + i % 2;
            }
            return dp;
        }

    }
}

12. 粉刷房子2

题目

class Solution {
    public int minCostII(int[][] costs) {
        int n = costs.length; // n个房子
        int k = costs[0].length; // k种颜色
        int[][] f = new int[n+1][k];
        int min1, min2;
        int j1 = 0;
        int j2 = 0;
        
        // dp[i][j] 油漆前i栋房子,并且i-1栋房子是j颜色的最小代价
        for(int j = 0; j < k; j++) {
            f[0][j] = 0;
        }
        for(int i = 1; i <= n; i++) {
            //最小值和次小值
            min1 = min2 = Integer.MAX_VALUE;
            for(int j = 0; j < k; j++) {
                if(f[i - 1][j] < min1) {
                    min2 = min1;
                    j2 = j1;
                    min1 = f[i - 1][j];
                    j1 = j;
                }else{
                    if(f[i - 1][j] < min2) {
                        min2 = f[i - 1][j];
                        j2 = j;
                    }
                }
            } 
            for(int j = 0; j < k; j++) {
                if(j == j1) {
                    f[i][j] = costs[i - 1][j] + min2;
                }else{
                    f[i][j] = costs[i - 1][j] + min1;
                }
            }         
        } 
        int res = Integer.MAX_VALUE;
        for(int i = 0; i < k; i++) {
            res = res < f[n][i] ? res : f[n][i];
        }
        return res;   
    }
}

13. 房屋盗窃

题目

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if(n == 1){
            return nums[0];
        }else if(n == 2){
            return Math.max(nums[0], nums[1]);
        }else{
            int[] f = new int[n];
            f[0] = nums[0];
            f[1] = Math.max(nums[0], nums[1]);
            for(int i = 2; i < n; i++) {
                f[i] = f[i - 2] + nums[i] > f[i - 1] ? f[i - 2] + nums[i] : f[i - 1];
            }
            return f[n - 1];

        }
    }
}

14. 房屋盗窃2

题目

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if (n == 1) {
            return nums[0];
        }else if(n == 2) {
            return Math.max(nums[0], nums[1]);
        }else if(n == 3){
            return Math.max(nums[0], Math.max(nums[1], nums[2]));
        }else{
            int[][] f = new int[n][2];
            f[0][0] = nums[0];
            f[0][1] = 0;
            f[1][0] = nums[0];
            f[1][1] = nums[1];
            f[2][0] = nums[0];
            f[2][1] = Math.max(nums[1], nums[2]);

            for(int i = 3; i < n; i++) {
                f[i][0] = Math.max(f[i - 1][0], f[i - 2][0]+ nums[i - 1]); 
                f[i][1] = Math.max(f[i - 1][1], f[i - 2][1]+ nums[i]); 
            }
            return Math.max(f[n - 1][0], f[n - 1][1]);
        }
           
    }
}

15. 股票的最大利润

题目

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;

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

    }
}
举报

相关推荐

0 条评论