[leetcode] 打家劫舍

本文完成题目:

打家劫舍

题目[198]:打家劫舍

与题目 按摩师 一模一样。

状态定义:dp1[i] 表示选择第 i 个时的最大收益;dp0[i] 表示不选择第 i 个时的最大收益。

转移方程:

// 不选择第 i 个,前一个可选可不选
dp0[i] = max(dp1[i-1], dp0[i-1])
// 选择第 i 个,前一个必然不能选
dp1[i] = dp0[i-1] + vals[i]

空间优化:

dp0 = max(dp1, dp0)
dp1 = dp0 + val[i]

代码:

int rob1(vector<int> &vals)
{
    if (vals.size() == 0)  return 0;
    int dp0 = 0, dp1 = vals[0], t;
    for (int i = 1; i < vals.size(); i++)
    {
        t = dp0;
        dp0 = max(dp0, dp1);
        dp1 = vals[i] + t;
    }
    return max(dp0, dp1);
}

打家劫舍 Ⅱ

题目[213]:打家劫舍 II

此处的附加条件是:房屋呈环形排列,第 0 号房屋与第 n-1 号房屋相邻(不能同时偷它们)。也就是说:

  • 如果想选择第 0 号房屋,就不能选择第 n-1 号房屋,只能从区间 [0, n-2] 中考虑。
  • 如果想选择第 n-1 号房屋,就不能选择第 0 号房屋,只能从区间 [1, n-1] 中考虑。

也就是说,基于第一题的实现,此处答案是 max(rob1(vals[0, ..., n-2]), rob1(vals[1, ..., n-1])) .

可能你还有一个疑问:假如第 0 号和第 n-1 号都不选才是最大的呢?

实际上,rob1(0, n-2) 已经考虑了这种情况,此处的 rob1 只是在该区间内的最大收益,并不一定是选择第 0 号房屋。rob1(1, n-1) 同理。

代码:

class Solution
{
public:
    int rob(vector<int> &nums)
    {
        int n = nums.size();
        if (n == 0)  return 0;
        if (n == 1)  return nums[0];
        if (n == 2)  return max(nums[0], nums[1]);
        return max(rob1(nums, 0, n-2), rob1(nums, 1, n-1));
    }
    int rob1(vector<int> &vals, int start, int end)
    {
        if (start == end)  return vals[start];
        int dp0 = 0, dp1 = vals[start], t;
        for (int i = start + 1; i <= end; i++)
        {
            t = dp0;
            dp0 = max(dp0, dp1);
            dp1 = vals[i] + t;
        }
        return max(dp0, dp1);
    }
};

打家劫舍 Ⅲ

题目[337]:打家劫舍 III

传说中的「树形DP」今天是终于遇上了😓。参考此处题解

状态定义

dp[node][0] 表示不选择 node 的最大值,dp[node][1] 表示选择 node 的最大值。

转移方程

由于是二叉树,所以必然是采取递归处理的(实际上需要采用后序遍历)。假设在求解根节点前,对根 node 的左右子树进行了同样操作,所得结果为 dp[left][0], dp[left][1], dp[right][0], dp[right][1]

  • 选择 node ,那么 node.leftnode.right 都不能选。
  • 不选 node ,那么 node.leftnode.right 选或不选都可以。

所以转移方程为:

dp[node][0] = max(dp[left][0], dp[left][1]) + max(dp[right][0], dp[right][1])
dp[node][1] = dp[left][0] + dp[right][0] + node.val

边界条件:dp[null][0] = dp[null][1] = 0 .

代码:

class Solution
{
public:
    int rob(TreeNode *root)
    {
        auto v = helper(root);
        return max(v[0], v[1]);
    }
    vector<int> helper(TreeNode *p)
    {
        if (p == nullptr)  return {0, 0};
        auto dpl = helper(p->left);
        auto dpr = helper(p->right);
        vector<int> dpnode(2);
        dpnode[0] = max(dpl[0], dpl[1]) + max(dpr[0], dpr[1]);
        dpnode[1] = p->val + dpl[0] + dpr[0];
        return dpnode;
    }
};

其实还能将 dpnode 部分 “缩” 得更短,更像 OI 风格一些:

return {max(dpl[0], dpl[1]) + max(dpr[0], dpr[1]), p->val + dpl[0] + dpr[0]};
posted @ 2020-06-07 20:30  sinkinben  阅读(225)  评论(1编辑  收藏  举报