打家劫舍 II

96 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、题目:

leetcode 打家劫舍 II

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

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

 

示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4

示例 3:

输入:nums = [1,2,3]
输出:3

提示:

1 <= nums.length <= 100
0 <= nums[i] <= 1000

二、题解:

1.解读

简而言之nums数组的元素值代表金额,你需要获取数组元素值的最大和就是最大的金额。规则是获取的每一个数组元素的下标不能连续,并且数组的头尾两个元素也看成连续的。也就是说如果取了数组第一个元素,那么数组第二个元素和数组最后一个元素都不能再取了,获取的每一个元素之间必须相隔一个以上的元素。

方法一

对于只有一间房屋的也就是数组只有一个元素的,则之间获取该元素值就是最大金额了。对于有两间房屋的数组有两个元素,由于不能获取相邻的元素,所以选择元素值较大的一个元素就是最大金额。对于房屋有三间以及三间以上的就需要考虑第一间房屋和最后一间房屋是相邻的情况,就是说数组的第一个元素和最后一个元素不能同时获取。如果数组获取了第一个元素,那最后一个元素就不能获取;如果获取了最后一个元素,那么第一个元素就不能再获取了。假如数组长度为n,不获取第一个元素时可取的范围为[1, n]获取的最大金额为num1,不获取最后一个元素时可取的范围为[0, n-1]获取的最大金额为num2,所以总的最大金额就取num1num2中较大的一个max(num1, num2)。具体的定义'dp'数组,'dp[i]'表示nums数组的前i间房屋能获取的最大金额,对于当前下标元素i,如果获取了第i - 1下标的元素,那么当前下标元素i不能获取了最大金额为dp[i - 1];如果要获取当前下标元素i,那么第i - 1下标的元素不可再获取最大金额就是dp[i - 2] + nums[i];应该取这二者的较大值,所以dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])。对于dp数组我们只使用了dp[i-1]和dp[i-2]的元素值,那么我们可以直接使用两个变量记录即可,可以省下额外的空间。

三、代码:

方法一 Java代码

class Solution {
    public int rob(int[] nums) {
        int length = nums.length;
        if (length == 1) {
            return nums[0];
        } 
        if (length == 2) {
            return Math.max(nums[0], nums[1]);
        }
        return Math.max(rob2(Arrays.copyOfRange(nums, 0, nums.length - 1)),
                rob2(Arrays.copyOfRange(nums, 1, nums.length)));
    }

    public int rob2(int[] nums) {
        int first = 0;
        int second = 0;
        for (int num : nums) {
            int temp = second;
            second = Math.max(first + num, second);
            first = temp;
        }
        return second;
    }
}

时间复杂度:O(n),需要两次遍历数组元素。

空间复杂度:O(1),只需要常数个空间变量。

四、总结

与之前198. 打家劫舍 差不多的。