LeetCode 198.打家劫舍

385 阅读2分钟

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

题目:一个小偷准备晚上偷东西,每家都会有一定数量的现金,但如果同时偷盗相邻的两家,则会发生报警。要求设计一个方法能使得小偷在一晚上偷到的现金最多。

解题思路

本题唯一的限制就是不能偷盗连续两家的,我们可以先使用几个小数据进行模拟。假设只有一家,则最大偷盗的就是那家的现金。假设只有两家,则会偷盗两家现金较多的那家。如果有三家,则会比较第一家和第三家的现金和与第二家哪个大,选择大的偷。那么如果有四家呢?此时的情况就变成偷盗以下情况最大的:

  1. 第一家和第三家
  2. 第二家和第四家
  3. 第一家和第四家

因此如果屋子的数量大于3,则我们可以使用动态规划来获取可偷盗的最大现金,我们首先假设如果存在i家屋子,则第i家的现金必须偷,此时状态转移方程dp[i]的含义就是如果确定偷当前屋子能最多偷多少。状态转移方程的更新为:

dp[i]=Math(dp[i2],dp[i3])+nums[i]dp[i] = Math(dp[i-2], dp[i-3]) + nums[i]

可得如下代码:

public int rob(int[] nums) {
        // dp含义 dp[i]表示如果确定偷当前屋子能最多偷多少
        if(nums==null||nums.length==0) return 0;
        if(nums.length==1) return nums[0];
        if(nums.length==2) return Math.max(nums[0], nums[1]);
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = nums[1];
        dp[2] = nums[0] + nums[2];
        int maxRob = Math.max(dp[1], dp[2]);
        for(int i=3;i<nums.length;i++){
            dp[i] = Math.max(dp[i-2], dp[i-3]) + nums[i];
        }
        for(int value:dp){
            maxRob = Math.max(value, maxRob);
        }
        return maxRob;
    }

上述代码时间复杂度和空间复杂度都是O(n)O(n)

可否换一种思路,题目要的是当有n间屋子时,所能偷的最大现金数量。那么我们是否可以直接定义动态转移方程的含义dp[i]就是当存在i间屋子时所能偷盗的最大现金数量,此时动态转移方程的更新就变为:

dp[i]=Math.max(dp[i2]+nums[i],dp[i1])dp[i] = Math.max(dp[i-2]+nums[i], dp[i-1])

可得如下代码:

public int rob2(int[] nums) {
        // dp的含义 dp[i]表示当有i间屋子时可偷最大数值
        if(nums==null||nums.length==0) return 0;
        if(nums.length==1) return nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for(int i=2;i<nums.length;i++){
            dp[i] = Math.max(dp[i-2] + nums[i] , dp[i-1]);
        }
        return dp[nums.length-1];
    }

代码的时间复杂度和空间复杂度还是O(n)O(n)