-
题目:
一个m*n的矩阵,每个格子上都放着一个礼物,且价值均 > 0;
从左上角走到右下角的所有路径中,返回价值的最大; -
思路:
1.暴力dfs递归:时间O(2 ^ (m*n)):指数时间复杂度超时,因为(除了第0行,第0列)其它每个格子需要递归2次,空间O(max(m,n)):对于一个格子,只能向右或者下,因为是dfs,所以这两个格子的递归用的是同一块系统栈;
class Solution {
public:
int res;
void dfs(vector<vector<int>>& grid, int i, int j, int m, int n, int val) {
val += grid[i][j];
if (i == m - 1 && j == n - 1) {
//成功到达右下角,就更新一下结果res
res = max(res, val);
return;
}
int dx[2] = {
0, 1}, dy[2] = {
1, 0};
for (int k = 0; k < 2; ++k) {
int ni = i + dx[k], nj = j + dy[k];
if (ni >= 0 && ni < m && nj >= 0 && nj < n) dfs(grid, ni, nj, m, n, val);
}
}
int maxValue(vector<vector<int>>& grid) {
if (!grid.size() || !grid[0].size()) return 0;
int m = grid.size(), n = grid[0].size();
res = 0;
dfs(grid, 0, 0, m, n, 0);
return res;
}
};
2.dp:时间O(mn),空间O(mn):额外需要一个m*n的dp矩阵
class Solution {
public:
int res;
int maxValue(vector<vector<int>>& grid) {
if (!grid.size() || !grid[0].size()) return 0;
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dp(m, vector<int>(n));//dp[i][j]表示从[0][0]走到[i][j]处获得的最大价值
dp[0][0] = grid[0][0];
for (int i = 1; i < m; ++i) dp[i][0] = dp[i - 1][0] + grid[i][0];
for (int i = 1; i < n; ++i) dp[0][i] = dp[0][i - 1] + grid[0][i];
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[i][j] = max(dp[i-1][j], dp[i][j - 1]) + grid[i][j];//从左或上过来
}
}
return dp[m-1][n-1];
}
};
//上面写法为了避免dp递推式中的i-1或j-1的越界问题,需要提前初始化第0行和第0列;
//yxc的写法:实际上,第0行第0列也是可以用dp递推式推出来的,但为了避免越界,可以整个矩阵多一行一列,直接从1开始数,这样i-1,j-1就是0,仍不会月越界,且由于grid中的数全部都是正数,可以保证dp递推式的max(0, 第一行或第一列中的某个数)=第一行或第一列中的该数
class Solution {
public:
int res;
int maxValue(vector<vector<int>>& grid) {
if (!grid.size() || !grid[0].size()) return 0;
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));//dp[i][j]表示从[0][0]走到[i-1][j-1]处获得的最大价值
for (int i = 1; i <= m; ++i) {
//这里走到m
for (int j = 1; j <= n; ++j) {
//这里走到n
dp[i][j] = max(dp[i-1][j], dp[i][j - 1]) + grid[i - 1][j - 1];//这里[i][j]对应grid中的i-1,j-1
}
}
return dp[m][n];
}
};
3.将dp数矩阵优化为一维的:时间O(m*n),O(n):只需要一个长为n的一维数组,逐行更新
class Solution {
public:
int res;
int maxValue(vector<vector<int>>& grid) {
if (!grid.size() || !grid[0].size()) return 0;
int m = grid.size(), n = grid[0].size();
vector<int> dp(n);//dp[j]表示从[0][0]走到当前[i][j]处的可获得的最大价值
for (int i = 0; i < m; ++i) {
//当前走到哪一行
for (int j = 0; j < n; ++j) {
//当前走到哪一列
if (j == 0) dp[j] += grid[i][0];//第0列只能从上边过来,因此需要单独考虑
else dp[j] = max(dp[j], dp[j - 1]) + grid[i][j];//其他地方都能从左(相当于自己的左边)和上(相当于自己)过来
}
}
return dp[n - 1];
}
};