【代码随想录刷题记录】198.打家劫舍 、 213.打家劫舍II 、 337.打家劫舍III

198.打家劫舍

1、题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

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

2、代码

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

    }
};

3、小结
根据第i家偷不偷的情况,来分类讨论不同情况下偷的的金额总数,最后取所有情况的最大值即可。需要注意dp[1]的初始化为nums[0]、nums[1]的最大值。

213.打家劫舍II

1、题目
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

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

2、代码

class Solution {
public:
    int robRange(vector<int>& nums, int start, int end){
        if(end == start) return nums[start];
        vector<int> 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 - 1], dp[i - 2] + nums[i]);
        }
        return dp[end];
    }
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        //考虑0号屋的情况
        int result1 = robRange(nums, 0, nums.size() - 2);
        //考虑size-1号屋的情况
        int result2 = robRange(nums, 1, nums.size() - 1);
        return max(result1, result2);
        

    }
};

3、小结
没必要考虑0号房子到底偷不偷,只需要考虑该房子是不是要纳入考虑,最后分两种情况进行动态规划的计算,再将得到的答案取最大值。

337.打家劫舍III

1、题目
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

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

2、代码

class Solution {
public:
    vector<int> traving(TreeNode* cur){
        if(cur == nullptr) return vector<int>{0, 0};

        vector<int> left = traving(cur -> left);
        vector<int> right = traving(cur -> right);
        int result1 = max(left[0], left[1]) + max(right[0], right[1]);//不偷cur,考虑最大值。
        int result2 = left[0] + right[0] + cur -> val;//偷cur

        return {result1, result2};
    }
    int rob(TreeNode* root) {
        if(root == nullptr) return 0;
        vector<int> result = traving(root);
        return max(result[0], result[1]);
    }
};

3、小结
使用动态规划和后序遍历的结合,记录下偷当前节点的金额最大值和不偷当前节点的金额最大值,并返回直到根节点返回两者中的最大值即可。

你可能感兴趣的:(leetcode,算法)