动态规划

状态转移方程是动态规划问题首先要找到的

174. Dungeon Game

思路:初始化一个dp数组,大小是整型的最大值,代表当前位置所需的最小血量

  • 首先初始化公主位置的右方、下方的值为1
  • 从公主所在位置开始,与右方、下方相比,找到当前位置所需的最小血量(正数:当前位置所需血量为1;负数:右方、下方最小血量与当前相减即可得到)
 1 // time:o(m*n)
 2 // space:o(m*n)
 3 class Solution {
 4     public int calculateMinimumHP(int[][] dungeon) {
 5         int len = dungeon[0].length;
 6         int dep = dungeon.length;
 7         int[][] dp = new int[dep + 1][len + 1];
 8         for (int i = 0; i <= dep; i++) {
 9             for (int j = 0; j <= len; j++) {
10                 dp[i][j] = Integer.MAX_VALUE;
11             }
12         }
13         dp[dep][len - 1] = 1;
14         dp[dep - 1][len] = 1;
15         for (int i = dep - 1; i >= 0; i--) {
16             for (int j = len - 1; j >= 0; j--) {
17                 // dp数组增加是为了方便编程,这样可以在遍历数组的时候直接使用i+1,j+1
18                 dp[i][j] = Math.max(1, Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]);
19             }
20         }
21         return dp[0][0];
22     }
23 }
View Code

注意:

  • 每次搜索当前位置最小血量时,要取最大值

303. Range Sum Query - Immutable

思路:使用一维数组记录记录原数组开始位置到当前位置的和

 1 // time: o(n) + m * o(1) = o (m + n) m次查询
 2 // space: o(n)
 3 class NumArray {
 4     
 5     private int[] dp;
 6 
 7     public NumArray(int[] nums) {
 8         dp = new int[nums.length + 1];
 9         for (int i = 0; i < nums.length; i++) {
10             dp[i + 1] = dp[i] + nums[i];
11         }
12     }
13     
14     public int sumRange(int i, int j) {
15         return dp[j + 1] - dp[i];
16     }
17 }
18 
19 /**
20  * Your NumArray object will be instantiated and called as such:
21  * NumArray obj = new NumArray(nums);
22  * int param_1 = obj.sumRange(i,j);
23  */
View Code

312. Burst Balloons

思路:动态规划_第1张图片

c[i][j]表示位置i与位置j之间最大的分数,将该问题分解为小问题

  • 选出最后一个要爆的气球位置k,此时可以将问题分解为c[i][k-1] + nums[i -1] * nums[k] * nums[j + 1] + c[k + 1][j]
  • 三层循环讲解如下:
  1. 小问题:c[i][j]长度最小1的开始,直到长度最大n-2
  2. i的选取,从1开始,可以一直取值到n-len - 1;j的值一定为left+len-1
  3. 开始循环,找到此时从i到j的最大值,此时小问题已经求出答案
 1 // time: o(n ^ 3)
 2 // space: o(n ^ 2)
 3 class Solution {
 4     public int maxCoins(int[] nums) {
 5         int[] mid = new int[nums.length + 2];
 6         int n = 1;
 7         for (int num : nums) {
 8             if (num > 0) {
 9                 mid[n++] = num;
10             }
11         }
12         mid[0] = mid[n++] = 1;
13         
14         int[][] dp = new int[n][n];
15         for (int len = 1; len <= n - 2; len++) {
16             for (int left = 1; left <= n - len - 1; left++) {
17                 int right = left + len - 1;
18                 for (int i = left; i <= right; i++) {
19                     dp[left][right] = Math.max(dp[left][right], dp[left][i - 1] + 
20                                                mid[left - 1] * mid[i] * mid[right + 1] + dp[i + 1][right]);
21                 }
22             }
23         }
24         return dp[1][n - 2];
25     }
26 }
View Code

注意:

  • 可以将原数组的0值去除

以下是另外一种解法

 1 class Solution {
 2     public int maxCoins(int[] nums) {
 3         int[] mid = new int[nums.length + 2];
 4         int n = 1;
 5         for (int num : nums) {
 6             if (num > 0) {
 7                 mid[n++] = num;
 8             }
 9         }
10         mid[0] = mid[n++] = 1;
11         int[][] mem = new int[n][n];
12         return burst(mem, mid, 1, n - 2);
13     }
14     private int burst(int[][] mem, int[] nums, int left, int right) {
15         if (mem[left][right] > 0) {
16             return mem[left][right];
17         }
18         int res = 0;
19         for (int i = left; i <= right; i++) {
20             res = Math.max(res, burst(mem, nums, left, i - 1) + 
21                            nums[left - 1] * nums[i] * nums[right + 1] + burst(mem, nums, i + 1, right));
22         }
23         mem[left][right] = res;
24         return res;
25     }
26 }
View Code

70. Climbing Stairs

思路:比较简单

 1 // time: o(n)
 2 class Solution {
 3     public int climbStairs(int n) {
 4         int[] res = new int[3];
 5         if (n <= 1) {
 6             return 1;
 7         }
 8         res[0] = res[1] = 1;
 9         for (int i = 2; i <= n; i++) {
10             res[i % 3] = res[(i - 1) % 3] + res[(i - 2) % 3];
11         }
12         return res[n % 3];
13     }
14 }
View Code

113. Path Sum II

思路:DFS

 1 /**
 2  * Definition for a binary tree node.
 3  * public class TreeNode {
 4  *     int val;
 5  *     TreeNode left;
 6  *     TreeNode right;
 7  *     TreeNode(int x) { val = x; }
 8  * }
 9  */
10 class Solution {
11     public List> pathSum(TreeNode root, int sum) {
12         List> res = new ArrayList<>();
13         List path = new ArrayList<>();
14         findSum(res, path, root, sum);
15         return res;
16     }
17     private void findSum(List> res, List path, TreeNode root, int sum) {
18         if (root == null) {
19             return;
20         }
21         sum = sum - root.val;
22         if (root.left == null && root.right == null) {
23             if (sum  == 0) {
24                 path.add(root.val);
25                 res.add(new ArrayList(path));
26                 // DFS一定要移除元素
27                 path.remove(path.size() - 1);
28             }
29             return;
30         }
31         path.add(root.val);
32         findSum(res, path, root.left, sum);
33         findSum(res, path, root.right, sum);
34         path.remove(path.size() - 1);
35     }
36 }
View Code

120. Triangle

思路:动规

 1 class Solution {
 2     public int minimumTotal(List> triangle) {
 3         int n = triangle.size();
 4         int[][] dp = new int[n][n];
 5         // dp[i][j] = minTotalOf(i, j) 表达式含义
 6         // 1、状态转移方程:dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle[i][j]
 7         for (int i = 0; i < n; i++) {
 8             for (int j = 0; j <= i; j++) {
 9                 dp[i][j] = triangle.get(i).get(j);
10                 // 2、边界条件
11                 if (i == 0 && j == 0) {
12                     continue;
13                 } else if (j == 0) {
14                     dp[i][j] += dp[i - 1][j];
15                 } else if (j == i) {
16                     dp[i][j] += dp[i - 1][j - 1];
17                 } else {
18                     dp[i][j] += Math.min(dp[i - 1][j], dp[i - 1][j - 1]);
19                 }
20             }
21         }
22         int res = Integer.MAX_VALUE;
23         for (int i = 0; i < n; i++) {
24             res = Math.min(res, dp[n - 1][i]);
25         }
26         return res;
27     }
28 }
View Code

方法二:自下而上的动规,节省空间space: o(n)

 1 class Solution {
 2     public int minimumTotal(List> triangle) {
 3         int n = triangle.size();
 4         int[] dp = new int[n];
 5         for (int i = 0; i < n; i++) {
 6             dp[i] = triangle.get(n - 1).get(i);
 7         }
 8         for (int k = n - 2; k >= 0; k--) {
 9             for(int i = 0; i <= k; i++) {
10                 dp[i] = Math.min(dp[i], dp[i + 1]) + triangle.get(k).get(i);
11             }
12         }
13         return dp[0];
14     }
15 }
View Code

 

你可能感兴趣的:(动态规划)