代码随想录训练营第四十八天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III

198.打家劫舍

题目链接:https://leetcode.cn/problems/house-robber/submissions/

代码:

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

方法二:

class Solution {
public:
    int rob(vector& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        vector dp(nums.size());
        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];
    }
};

两种方法从dp[1]开始不一样

213.打家劫舍II

题目链接:https://leetcode.cn/problems/house-robber-ii/submissions/

代码:

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

对于一个数组,成环的话主要有如下三种情况:

  • 情况一:考虑不包含首尾元素

代码随想录训练营第四十八天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III_第1张图片
  • 情况二:考虑包含首元素,不包含尾元素

代码随想录训练营第四十八天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III_第2张图片
  • 情况三:考虑包含尾元素,不包含首元素

代码随想录训练营第四十八天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III_第3张图片

注意我这里用的是"考虑",例如情况三,虽然是考虑包含尾元素,但不一定要选尾部元素! 对于情况三,取nums[1] 和 nums[3]就是最大的。

而情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了

337.打家劫舍III

题目链接:https://leetcode.cn/problems/house-robber-iii/submissions/

代码(暴力解法):

class Solution {
public:
    int rob(TreeNode* root) {
        if(root == nullptr)
            return 0;
        int val1 = root->val;
        if(root->left)
            val1 += rob(root->left->right) + rob(root->left->left);
        if(root->right)
            val1 += rob(root->right->right) + rob(root->right->left);
        int val2 = rob(root->left) + rob(root->right);
        if(val2 > val1)
            return val2;
        else
            return val1;
    }
};

代码:

class Solution {
public:
    // 长度为2的数组,0:不偷,1:偷
    vector robTree(TreeNode* cur)
    {
        if(cur == nullptr)
            return vector{0,0};
        vector left = robTree(cur->left);
        vector right = robTree(cur->right);
        // 偷cur,那么就不能偷左右节点
        int val1 = cur->val + left[0] + right[0];
        // 不偷cur
        int val2 = max(left[0],left[1]) + max(right[0],right[1]);
        return vector{val2,val1};
    }
    int rob(TreeNode* root) {
        vector result = robTree(root);
        if(result[0] > result[1])
            return result[0];
        else
            return result[1];
    }
};

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

分情况讨论

你可能感兴趣的:(c++)