剑指 Offer 47. 礼物的最大价值
题目:
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
提示:
0 < grid.length <= 200
0 < grid[0].length <= 200
解题历程
DFS
深度优先搜索所有到达终点的路径,并解
class Solution {
//礼物最大值
int res = Integer.MIN_VALUE;
//DFS路径
List<Integer> route = new ArrayList<>();
public int maxValue(int[][] grid) {
DFS(grid, 0, 0);
return res;
}
/**
* 深度优先搜索
*/
private void DFS(int[][] grid, int i, int j) {
if (i >= grid.length || j >= grid[0].length) {
return;
}
//添加礼物
route.add(grid[i][j]);
//到达终点
if (i == grid.length - 1 && j == grid[0].length - 1) {
//计算本路径值
int routeVal = 0;
for (Integer e : route) {
routeVal += e;
}
//礼物最大值选取最大值
res = Math.max(routeVal, res);
}
DFS(grid, i, j + 1);
DFS(grid, i + 1, j);
//去除本层节点
route.remove(route.size() - 1);
}
}
结果:
时间复杂度超了!!!
分析一下:
除去边缘节点,每个节点基本都存在两个方向的后继节点。若节点数为N,则为O(2^N),马老师说,停停 !!你这里还包含时间复杂度O(N^1/2)的加法运算!!!
OK ,那么先省略掉这里的加法运算:
class Solution {
//礼物最大值
int res = Integer.MIN_VALUE;
public int maxValue(int[][] grid) {
DFS(grid, 0, 0, 0);
return res;
}
//val 前路径中和数
private void DFS(int[][] grid, int i, int j, int val) {
if (i >= grid.length || j >= grid[0].length) {
return;
}
//添加礼物
val += grid[i][j];
//
if (i == grid.length - 1 && j == grid[0].length - 1) {
res = Math.max(val, res);
}
DFS(grid, i, j + 1, val);
DFS(grid, i + 1, j, val);
}
}
结果:
分析一下:
可以肯定的是本题时间复杂度必定不允许O(2^N)
翻翻评论区,看看别人的思路吧!!(小可耻!!)
对啊,动态规划啊,这个问题就和70. 爬楼梯问题是一摸一样!!( 爬楼梯问题严格意义上其实不属于动态规划)
状态转移方程如下:
DP(i,j)=Math.max(DP(i-1,j),DP(i,j-1))+NUM(i,j);
递归实现:
class Solution {
public int maxValue(int[][] grid) {
return dp(grid, grid.length - 1, grid[0].length - 1);
}
private int dp(int[][] grid, int i, int j) {
if (i < 0 || j < 0) {
return 0;
}
return Math.max(grid[i][j] + dp(grid, i - 1, j), grid[i][j] + dp(grid, i, j - 1));
}
}
不敢说代码实现和爬楼梯问题十分相识,简直一摸一样吧!
然鹅结果:
问题就在于没有消灭重复子问题,就拿爬楼梯问题中的f(4)=f(3)+f(2),而f(3)=f(2)+f(1),… 那么其中的f(2)就计算了多次导致的。
迭代法实现:
class Solution {
public int maxValue(int[][] grid) {
int[][] dpTable = new int[grid.length][grid[0].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
int val=0;
if(i-1>=0){
val = Math.max(val, dpTable[i - 1][j]);
}
if(j-1>=0){
val = Math.max(val, dpTable[i][j - 1]);
}
dpTable[i][j]=grid[i][j]+val;
}
}
return dpTable[grid.length - 1][grid[0].length - 1];
}
}
结果: