打家劫舍(House Robber)是LeetCode上比较典型的一个题目,涉及三道题,主要解题思想是动态规划,将三道题依次记录如下:

(一)打家劫舍

题目等级:198、House Robber(Easy)

题目描述:

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.

Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.

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


解题思路:

  本题实际就是典型的动态规划问题,沿街的房屋依次决定每一家偷还是不偷为一个阶段,用dp[i]表示前i家获取的最高金额,第i阶段的决策就是两种:偷、不偷。则不难写出以下状态转移方程:

  dp[i]=max(dp[i-1],dp[i-2]+nums[i])

  从以上的递推公式可以看出,第i个状态只和i-1和i-2两个状态有关,因此,也可以省略掉数组,只维护两个变量即可。

//解法一:动态规划(数组)
class Solution {
public int rob(int[] nums) {
//典型的动态规划问题,dp[i]=max(dp[i-1],dp[i-2]+nums[i])
//每个阶段确定一家偷还是不偷,所以决策就是偷和不偷两种
if(nums==null || nums.length==0)
return 0;
int len=nums.length;
int[] res=new int[len+1];
res[0]=0;
res[1]=nums[0];
for(int i=2;i<=len;i++){
res[i]=Math.max(res[i-1],res[i-2]+nums[i-1]); //状态转移
}
return res[len];
}
} //解法二:动态规划(维护两个变量)
class Solution {
public int rob(int[] nums) {
//dp[i]表示前i家可以得到的最高金额,dp[i]=Max(dp[i-1],dp[i-2]+nums[i])
if(nums==null || nums.length==0)
return 0; int first=0,second=0,res=0;
for(int i=0;i<nums.length;i++){
res=Math.max(first+nums[i],second);
first=second;
second=res;
}
return res;
}
}

(二)打家劫舍 II

题目等级:213、House Robber II(Medium)

题目描述:

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
because they are adjacent houses.

Example 2:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.

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


解题思路:

  本题和上题基本类似,区别在于:所有的房子围成一个圈,意味着首尾两家也属于相邻。

  基本思路当然还是动态规划,可以划分成两种情况来做,以第一家是否被偷为依据分成两个动态规划问题,如果第一家偷,那么从第一家到第n-1家求最大值(因为意味着最后一家一定不能偷);如果第一家不偷,那么从第2家到第n家求最大值。最后再比较两种情况的最大值即可。

class Solution {
public int rob(int[] nums) {
/*
思路:由于首尾也属于相邻,因此需要分别判断,以第一家是否打劫分成两个问题
第一家抢:最后一家一定不能抢,从第0个到len-2做动态规划
第一家不抢:从1到len-1做动态规划
然后比较找出最大值
*/
if(nums==null || nums.length==0)
return 0;
int len=nums.length;
if(len==1)
return nums[0];
int[] dp1=new int[len];
int[] dp2=new int[len+1];
//第一家抢
dp1[0]=0;
dp1[1]=nums[0];
for(int i=2;i<len;i++)
dp1[i]=Math.max(dp1[i-1],dp1[i-2]+nums[i-1]); //第一家不抢
dp2[0]=0;
dp2[1]=0;
for(int i=2;i<=len;i++)
dp2[i]=Math.max(dp2[i-1],dp2[i-2]+nums[i-1]); return Math.max(dp1[len-1],dp2[len]);
}
}

(三)打家劫舍 III

题目等级:337、House Robber III(Medium)

题目描述:

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:

Input: [3,2,3,null,3,null,1]

     3
/ \
2 3
\ \
3 1 Output: 7
Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:

Input: [3,4,5,1,3,null,1]

     3
/ \
4 5
/ \ \
1 3 1 Output: 9
Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9.

  题意:在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警


解题思路:

  和上两题不同的是:本题是二叉树形状,树中直接相连(也就是父子节点)不能同时打劫。

  实际上,有上一题的经验,我们不难找到规律:这里可以按根结点是否打劫分为两种情况,如果根结点被打劫,那么意味着它的子节点都不能打劫,需要直接打劫其孙子辈节点;如果根结点不打劫,那么可以考虑其左右孩子。同时,由于树的特性,左右子树都是子问题,因此实际上就是两种情况分别递归

class Solution {
public int rob(TreeNode root) {
/*
按根偷不偷,分两种情况,分别递归
*/
if(root==null)
return 0;
int res1=0;
//根在结果中
res1+=root.val;
if(root.left!=null)
res1+=(rob(root.left.left)+rob(root.left.right));
if(root.right!=null)
res1+=(rob(root.right.left)+rob(root.right.right)); //根不在结果中
int res2=rob(root.left)+rob(root.right);
return Math.max(res1,res2);
}
}

【LeetCode】打家劫舍系列(I、II、III)的更多相关文章

  1. LeetCode Single Number I / II / III

    [1]LeetCode 136 Single Number 题意:奇数个数,其中除了一个数只出现一次外,其他数都是成对出现,比如1,2,2,3,3...,求出该单个数. 解法:容易想到异或的性质,两个 ...

  2. LeetCode: Combination Sum I && II && III

    Title: https://leetcode.com/problems/combination-sum/ Given a set of candidate numbers (C) and a tar ...

  3. Leetcode 137. Single Number I/II/III

    Given an array of integers, every element appears twice except for one. Find that single one. 本题利用XO ...

  4. 团灭 LeetCode 打家劫舍问题

    有读者私下问我 LeetCode 「打家劫舍」系列问题(英文版叫 House Robber)怎么做,我发现这一系列题目的点赞非常之高,是比较有代表性和技巧性的动态规划题目,今天就来聊聊这道题目. 打家 ...

  5. 【一天一道LeetCode】#260. Single Number III

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  6. 买卖股票的最佳时机I II III IV

    I 假设有一个数组,它的第i个元素是一支给定的股票在第i天的价格.如果你最多只允许完成一次交易(例如,一次买卖股票),设计一个算法来找出最大利润. II 假设有一个数组,它的第i个元素是一个给定的股票 ...

  7. [array] leetcode - 40. Combination Sum II - Medium

    leetcode - 40. Combination Sum II - Medium descrition Given a collection of candidate numbers (C) an ...

  8. 【一天一道LeetCode】#90. Subsets II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  9. LeetCode 137. Single Number II(只出现一次的数字 II)

    LeetCode 137. Single Number II(只出现一次的数字 II)

  10. LeetCode:路径总和II【113】

    LeetCode:路径总和II[113] 题目描述 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径. 说明: 叶子节点是指没有子节点的节点. 示例:给定如下二叉树, ...

随机推荐

  1. 内置对象-Math

    1.随机数 Math.random() 1)获得0-1之间的随机数 2)0到100:Math.round(Math.random()*100) 2.max:求最大值 ,,,) console.log( ...

  2. BZOJ 2243: [SDOI2011]染色 (树剖+线段树)

    树链剖分后两个区间合并的时候就判一下相交颜色是否相同来算颜色段数就行了. CODE #include <vector> #include <queue> #include &l ...

  3. BZOJ 2152 / Luogu P2634 [国家集训队]聪聪可可 (点分治/树形DP)

    题意 一棵树,给定边权,求满足两点之间的路径上权值和为3的倍数的点对数量. 分析 点分治板题,对每个重心求子树下面的到根的距离模3分别为0,1,2的点的个数就行了. O(3nlogn)O(3nlogn ...

  4. js比较两个时间的大小

    function checkdate(s,e){ //得到日期值并转化成日期格式,replace(/-/g, "//")是根据验证表达式把日期转化成长日期格式,这样再进行判断就好判 ...

  5. 【C#-多线程】实现每隔一段时间执行代码(多线程) 3种定时器

    总结以下三种方法,实现c#每隔一段时间执行代码: 方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间: 方法二:使用System.Timers.Timer类: 方法三:使用Sys ...

  6. Servlet中关于路径的小结

    URL(统一 资源定位符).URI(统一资源标识符)都是由资源路径和资源名称组成.   访问路径按照路径是否可以独立完成资源准确定位的判别标准,可以将访问路径分为绝对路径与相对路径. 关系:绝对路径 ...

  7. 验证码生成 C#

    /// <summary> /// 验证码类 /// </summary> public class Rand { #region 生成随机数字 /// <summary ...

  8. 【CUDA 基础】3.1 CUDA执行模型概述

    title: [CUDA 基础]3.1 CUDA执行模型概述 categories: CUDA Freshman tags: CUDA SM SIMT SIMD Fermi Kepler toc: t ...

  9. CF762F Tree nesting

    题目连接 问题分析 可以给小树钦定一个根, \(Dp[i][j]\) 表示大树上的点 \(i\) 对应到小树上的点 \(j\) 的可能的方案数.然后每一步转移都是一个状压DP(将小树是否被匹配状压,然 ...

  10. VS下创建网站发布到IIS

    http://www.51zxw.net/show.aspx?id=27297&cid=410