动态规划的实质: 根据小问题的结果来判断大问题的结果
- 记忆化搜索
- 避免中间重复的计算结果
什么时候使用动态规划:
- 求最大最小值
- 判断是否可行
- 统计方案个数
什么时候不用动态规划:
- 求出所有具体的方案而非方案个数
- 输入数据是一个集合而不是序列
- 暴力算法的复杂度已经是多项式级别
- 动态规划擅长优化指数级别复杂度(2^n, n!)到多项式级别复杂度(n^2, n^3)
- 不擅长优化n^3到n^2
动态规划4要素
- 状态 存储小规模问题的结果
- 方程 状态之间的联系,怎么通过小的状态来算大的状态
- 初始化 最极限的小状态是什么,起点
- 答案 最大的那个状态是什么,终点
面试中动态规划类型:
1. 坐标型动态规划
state:
f[x]表示我从起点走到坐标x....
f[x][y] 表示我从起点走到坐标x,y....
function: 研究走到x,y这个点之前的一步
initialize: 起点
answer:终点
1.1 Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
1 public class Solution {
2 public int minPathSum(int[][] grid) {
3 if (grid == null || grid.length == 0 || grid[0].length == 0) {
4 return 0;
5 }
6
7 //initialize
8 int m = grid.length;
9 int n = grid[0].length;
10 int[][] sum = new int[m][n];
11 sum[0][0] = grid[0][0];
12
13 for (int i = 1; i < m; i++) {
14 sum[i][0] = grid[i][0] + sum[i - 1][0];
15 }
16
17 for (int i = 1; i < n; i++) {
18 sum[0][i] = grid[0][i] + sum[0][i - 1];
19 }
20
21 //dp
22 for (int i = 1; i < m; i++) {
23 for (int j = 1; j < n; j++) {
24 sum[i][j] = grid[i][j] + Math.min(sum[i - 1][j] , sum[i][j - 1]);
25 }
26 }
27 return sum[m - 1][n -1];
28 }
29 }
注意: 对于二维数组的判断, a == NULL || a.length == 0 || a[0].length == 0
state: f[x][y] 从起点走到x,y的最小路径
function: f[x][y] = min(f[x - 1][y], f[x][y - 1]) + A[x][y];
initialize: f[i][0] = sum(0,0~i,0)
f[0][i] = sum(0,0~0,i)
answer: f[m - 1][n - 1]
记住: 初始化一个二位的动态规划时,就去初始化第0行和第0列
1.2 Unique Paths
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
1 public class Solution { 2 public int uniquePaths(int m, int n) { 3 if (m == 0 || n == 0) { 4 return 0; 5 } 6 7 int[][] sum = new int[m][n]; 8 for (int i = 0; i < m; i++) { 9 sum[i][0] = 1; 10 } 11 for (int i = 0; i < n; i++) { 12 sum[0][i] = 1; 13 } 14 for (int i = 1; i < m; i++) { 15 for (int j = 1; j < n; j++) { 16 sum[i][j] = sum[i - 1][j] + sum[i][j - 1]; 17 } 18 } 19 return sum[m - 1][n - 1]; 20 } 21 }