21-4-15 打家劫舍 I && II

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

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

示例 1:

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

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12

提示:

0 <= nums.length <= 100
0 <= nums[i] <= 400

方法:动态规划

  1. 定义状态 f[i][j] : 表示到第 i 个房间 ,状态为j(j == 0表示不选,j == 1表示选)时的最大价值。

  2. 定义状态转移方程

    f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 0 ] ) f[i][0]=max(f[i-1][1],f[i-1][0]) f[i][0]=max(f[i1][1],f[i1][0])

    f [ i ] [ 1 ] = f [ i − 1 ] [ 0 ] + n u m s [ i ] f[i][1]=f[i-1][0]+nums[i] f[i][1]=f[i1][0]+nums[i]

下附代码👇

class Solution {
    public int rob(int[] nums) {
        int n =nums.length;
				//俩个边界判断
        if(n==0) return 0;
        if(n==1) return nums[0];
				//定义状态
        int [][] f =new int[n][2];
				//给起点赋初值
        f[0][0]=0;
        f[0][1]=nums[0];
				
        for(int i=1;i<n;i++){
            f[i][0]=Math.max(f[i-1][0],f[i-1][1]);
            f[i][1]=f[i-1][0]+nums[i];
        }
				//最终答案在选和不选最后一个房间中找寻最大价值
        return Math.max(f[n-1][0],f[n-1][1]);
    }
}

213. 打家劫舍 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 = [0]
输出:0

提示:

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

Ⅱ对于Ⅰ来说多增加了前后房间相邻的条件,也就是说,如果选了第一间房那么最后一间将无法再选,反之可以选择。

使用我们在此时应该分情况对 第一间房最后一间房的选取与否分情况讨论。

  • 选取 第一间房 的情况:
    f[0][0]=0
    f[0][1]=nums[0]
    此时最大价值应该为 m a x ( f [ n − 2 ] [ 1 ] , f [ n − 2 ] [ 0 ] ) max(f[n-2][1],f[n-2][0]) max(f[n2][1],f[n2][0])
  • 不选取 第一间房 的情况:
    f[0][0]=0
    f[0][1]=0
    此时最大价值应该为 m a x ( f [ n − 2 ] [ 1 ] , f [ n − 2 ] [ 0 ] + n u m s [ n − 1 ] ) max(f[n-2][1],f[n-2][0]+nums[n-1]) max(f[n2][1],f[n2][0]+nums[n1])

最终结果应该为 m a x ( 选 取 第 一 间 房 , 不 选 取 第 一 件 房 ) max(选取第一间房,不选取第一件房) max(,)

class Solution {
     public int rob(int[] nums) {
        int n =nums.length;
        if(n==0) return 0;
        if(n==1) return nums[0];
        int [][] f =new int[n][2];

				//不选取第一间房
        f[0][0]=0;
        f[0][1]=0;
        for(int i=1;i<n-1;i++){
            f[i][0]=Math.max(f[i-1][0],f[i-1][1]);
            f[i][1]=f[i-1][0]+nums[i];
        }
        int ans = Math.max(f[n-2][1],f[n-2][0]+nums[n-1]);

				//选取第一间房
        f[0][0]=0;
        f[0][1]=nums[0];
        for(int i=1;i<n-1;i++){
            f[i][0]=Math.max(f[i-1][0],f[i-1][1]);
            f[i][1]=f[i-1][0]+nums[i];
        }
        ans = Math.max(ans,Math.max(f[n-2][1],f[n-2][0]));

        return ans;
    }
}

当然根据观察会发现,起始f[i][j]的值只依赖 f[i-1][j],所以可以把空间缩小为o(1)

class Solution {
     public int rob(int[] nums) {
        int n =nums.length;
        if(n==0) return 0;
        if(n==1) return nums[0];
        int [][] f =new int[2][2];
        //不选第一间房
        f[0][0]=0;
        f[0][1]=0;
        for(int i=1;i<n-1;i++){
            f[i%2][0]=Math.max(f[(i-1)%2][0],f[(i-1)%2][1]);
            f[i%2][1]=f[(i-1)%2][0]+nums[i];
        }
        int ans = Math.max(f[(n-2)%2][1],f[(n-2)%2][0]+nums[n-1]);

        //选第一间房
        f[0][0]=0;
        f[0][1]=nums[0];
        for(int i=1;i<n-1;i++){
            f[i%2][0]=Math.max(f[(i-1)%2][0],f[(i-1)%2][1]);
            f[i%2][1]=f[(i-1)%2][0]+nums[i];
        }
        ans = Math.max(ans,Math.max(f[(n-2)%2][1],f[(n-2)%2][0]));

        return ans;
    }
}

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值