代码随想录刷题第48天|LeetCode198打家劫舍、LeetCode213打家劫舍II、LeetCode337打家劫舍III

1、LeetCode198打家劫舍

题目链接:198、打家劫舍

1、dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]

2、递推公式:

如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ;

如果不偷第i房间,那么dp[i] = dp[i - 1];

然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])。

3、初始化:

递推公式的基础就是dp[0] 和 dp[1]。

dp[0] = nums[0];

dp[1] = max(nums[0], nums[1]);

4、遍历顺序: 从前向后遍历;

5、举例推导。

class Solution {
public:
    int rob(vector& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        vector dp(nums.size(), 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < nums.size(); i++)
        {
            dp[i] = max(dp[i-2] + nums[i], dp[i-1]);
        }
        return dp[nums.size() - 1];
    }
};

2、LeetCode213打家劫舍II

题目链接:213、打家劫舍II

本题首尾连在一起,成环有三种情况:

考虑不包含首尾元素, 考虑包含首元素不包含尾元素, 考虑包含尾元素不包含首元素。

第二第三中情况包括第一种,所以只需考虑去掉首元素,去掉尾元素,这两种情况下,哪种的dp[i]更大。

递归五部曲与上题一样,由于要去掉首尾元素,定义一个start、end区间

robRange(vector& nums, int start, int end)。

class Solution {
public:
    int rob(vector& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];

        int result1 = robrange(nums, 0, nums.size()-2);
        int result2 = robrange(nums, 1, nums.size()-1);
        return max(result1, result2);
    }

    int robrange(vector& nums, int start, int end)
    {
        if (start == end) return nums[start];
        vector dp(nums.size(), 0);
        dp[start] = nums[start];
        dp[start+1] = max(nums[start], nums[start+1]);
        for (int i = start + 2; i <= end; i++)
        {
            dp[i] = max(dp[i-2] + nums[i], dp[i-1]);
        }
        return dp[end];
    }
};

3、LeetCode337打家劫舍III

题目链接:337、打家劫舍III

第一次做树形dp,有点难理解。

1、dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

2、递归树时的终止条件:

如果遇到空节点的话,无论偷还是不偷都是0。

if (cur == NULL)  return vector{0,0};    注意这里是花括号。

3、遍历顺序:

后序遍历。

递归左节点,得到左节点偷与不偷的金钱。

递归右节点,得到右节点偷与不偷的金钱。

4、递推公式:

偷该节点,则左右孩子不能偷,int val1 = cur->val + left[0] + left[1];

不偷该节点,则左右孩子要偷,每个孩子里偷一个最大的,int val2 = max(left[0],left[1]) + max(right[0], right[1]);

最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}。

5、举例推导:

代码随想录刷题第48天|LeetCode198打家劫舍、LeetCode213打家劫舍II、LeetCode337打家劫舍III_第1张图片

 

class Solution {
public:
    int rob(TreeNode* root) {
        vector result = robTree(root);
        return max(result[0], result[1]);
    }

    vector robTree(TreeNode* cur)
    {
        if (cur == NULL) return vector{0,0};
        vector left = robTree(cur->left);
        vector right = robTree(cur->right);

        int val1 = cur->val + left[0] + right[0];

        int val2 = max(left[0], left[1]) + max(right[0], right[1]);

        return {val2,val1};
    }
};

你可能感兴趣的:(算法,动态规划)