剑指offer Leetcode 47.礼物的最大价值

image-20201215094636152

解法:动态规划(非原地修改)

思想:

​ ●状态定义:dp[i][j]为以grid[i - 1][j - 1]为结尾的路径的最大值

​ ●转移方程:到当前点只能从上面和左边来,所以选两者中最大的。

dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];

​ ●初始状态:新建双层vector比grid大一行一列,在上边和左边加了一排0,所以dp[i][j]对应着grid[i - 1][j - 1]

​ ●返回值:返回dp[m][n]

复杂度:

​ ●时间:O(m*n),每个点遍历一次

​ ●空间:O(m*n),新建dp数组,可以优化(见下方)

代码:
class Solution {
public:
    int maxValue(vector<vector<int>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0)
            return 0;
        int m = grid.size(), n = grid[0].size();
        //m + 1, n + 1
        vector<vector<int>>dp(m + 1, vector<int>(n + 1, 0));
        //双层循环更新
        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 - 1][j - 1];
            }
        return dp[m][n];
    }
};
优化:滚动数组,空间优化至O(n)

因为求当前点的值只需要知道上一行和左边的值,所以可以用滚动数组来优化

class Solution {
public:
    int maxValue(vector<vector<int>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0)
            return 0;
        int m = grid.size(), n = grid[0].size();
        //建立一维dp
        vector<int>dp(n + 1, 0);
        for(int i = 1; i <= m; ++i)
            for(int j = 1; j <= n; ++j){
                //该句执行前dp[j]还是上一行的值,而dp[j - 1]是当前行左边的值
                dp[j] = max(dp[j - 1], dp[j]) + grid[i - 1][j - 1];
            }
        return dp[n];
    }
};

解法:动态规划(原地修改)

思想:

​ 在边界时只能通过左边或者上边中的一个到达

复杂度:

​ ●时间:O(m*n),每个点遍历一次

​ ●空间:O(1)

代码:
class Solution {
public:
    int maxValue(vector<vector<int>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0)
            return 0;
        int m = grid.size(), n = grid[0].size();
        //原地修改,不能用dp[i][j]对应grid[i - 1][j - 1],所以需要判断特殊情况
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < n; ++j){
                if(i == 0 && j == 0)
                    continue;
                else if(i == 0)
                    grid[i][j] += grid[i][j - 1];
                else if(j == 0)
                    grid[i][j] += grid[i - 1][j];
                else    
                    grid[i][j] += max(grid[i - 1][j], grid[i][j - 1]);
            }
        return grid[m - 1][n - 1];
    }
};

我的解法:DFS(能用但是效率太低,所以还是用动态规划)

思想:DFS
复杂度:

​ ●时间:遍历O(n)个节点,每个节点花费O(n)

代码:
class Solution {
private:
    int max_gift = 0;
public:
    int maxValue(vector<vector<int>>& grid) {
        if(grid.empty() || grid[0].empty())
            return 0;
        dfs(grid, 0, 0, 0);
        return max_gift;
    }
    //cur_gift不能传引用,防止互相干扰
    void dfs(vector<vector<int>>& grid, int row, int column, int cur_gift){
        //溢出判断
        if(row < 0 || row >= grid.size() || column < 0 || column >= grid[0].size())
            return;
        cur_gift += grid[row][column];
        //到右下角来比较
        if(row == (grid.size() - 1) && column == (grid[0].size() - 1))
            max_gift = max(cur_gift, max_gift);
        dfs(grid, row + 1, column, cur_gift);
        dfs(grid, row, column + 1, cur_gift);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值