前言
动态规划思想如何得到?为什么以下就想到动态规划?可以先DFS打个基础,然后体会其中的缺点,然后剪枝改进,递归再转迭代,那么就是经典的动态规划了。
一、礼物最大价值
二、DFS演变成动态规划
1、DFS
//礼物的最大价值
public class MaxValue {
/*
路径上能拿到的礼物的总价值最大为多少?
1.如何走完一条路径?有起点有终点,component-DFS完成路径上的礼物收集。
2.如何拿到最大价值?记录最大价值,每次到一条路径的终点时更新最大价值。
总结:component-DFS + 记录最大值。
*/
public int maxValue(int[][] grid) {
dfs(grid, 0, 0, 0);
return maxValue;
}
private void dfs(int[][] grid, int i, int j, int value) {
int m = grid.length, n = grid[0].length;
value += grid[i][j];
if (i == m - 1 && j == n - 1) {
if (maxValue < value) maxValue = value;
return;
}
//向右走
if (j + 1 < n) dfs(grid, i, j + 1, value);
//向下走
if (i + 1 < m) dfs(grid, i + 1, j, value);
}
int maxValue = 0;//最大礼物价值
}
2、DFS+剪枝
/*
改进
问题所在:有些共同路径被多次访问,但是由于需走到终点去更新maxValue,所以会重复走很多次,所以需要剪枝。
如何剪枝?-idea:如果知道以该点做为终点,找到了最大价值,那么其它路过来发现价值比其低,就没必要走接下来的公共路径了。
右下走,那么取左上来的最大值,要么走上面来的路径,要么走左边来的路径,这样就进行了剪枝,避免不必要走的重复公共路径。
用空间换时间,记录上和左的最大价值,然后获得当前位置的最大价值,通过Math.max来剪掉一条路径。
*/
class MaxValue2 {
//递归转迭代,用空间记录来剪枝。
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
for (int i = 1; i < m; i++) grid[i][0] += grid[i - 1][0];
for (int i = 1; i < n; i++) grid[0][i] += grid[0][i - 1];
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
return grid[m - 1][n - 1];
}
}
总结
1)DFS
2)递归转迭代+如何剪枝?
3)动态规划
参考文献
[1] LeetCode 礼物最大价值