您的位置:首页 > 其它

Leetcode 198. House Robber & 213. House Robber II & 337. House Robber III

2016-05-30 11:50 399 查看


198. House Robber

Total Accepted: 71597 Total
Submissions: 206073 Difficulty: 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.

必然是用DP。所有叙述当前房屋=今天,前一个房屋等于昨天,以此类推。

一开始觉得,今天到底来自前天还是昨天,昨天用没用 value,我怎么知道,于是建立了俩数组,自然是AC。

public class Solution {
public int rob(int[] nums) {
if(nums==null || nums.length==0) return 0;
if(nums.length==1) return nums[0];
if(nums.length==2) return nums[1]>nums[0] ? nums[1] : nums[0];

int[] res = new int[nums.length];
boolean[] flag = new boolean[nums.length];
// 初始化
res[0]=nums[0]; flag[0]=true;
if(nums[1]>nums[0]){
res[1]=nums[1]; flag[1]=true;
}else{
res[1]=nums[0]; flag[1]=false;
}
// 初始化完
for(int i=2; i<res.length; i++){
if(flag[i-1]==true){
int temp=res[i-2]+nums[i];
if(temp>res[i-1]){
flag[i]=true;
res[i]=temp;
}else{
flag[i]=false;
res[i]=res[i-1];
}
}else{
res[i]=res[i-1]+nums[i];
flag[i]=true;
}
}
return res[res.length-1];
}
}

然而网上的版本如下:
public class Solution {
public int rob(int[] num) {
if (num==null || num.length==0) return 0;
int maxToPos[] = new int[num.length+1]; //the maximum amount to the i'th house
maxToPos[0] = 0;
maxToPos[1] = num[0];
for (int i=2; i<maxToPos.length; i++){
maxToPos[i] = Math.max(maxToPos[i-1],maxToPos[i-2]+num[i-1]);
}
return maxToPos[maxToPos.length-1];
}
}

简单明了。于是想了一阵子怎么回事。首先如果是当前元素和前天结果,没问题, 不可能相邻;如果只取昨天的结果,不要今天元素,没问题,不冲突。问题是:如果昨天的结果其实没用昨天的元素,那么今天就可以加今天的元素了,那么不就漏掉一种CASE? 从AC的结果来看,肯定是没有漏。为什么?

比如就4天。1,2,3,4。今天是4,那么今天的结果有可能来自结果2+元素4或者结果3。有没有可能3结果中没用3呢?3的结果是1结果+元素3和2结果中的最大值。首先,1和2一定是满足不连续的规则,因为是头两天。那么如果3的结果不包含元素3,3只能来自结果2。如果没懂,换句话说,当结果3中不包含元素3的时候,那么结果3和结果2是一样的!所以对于结果4的判断,没有漏掉任何CASE。


213. House Robber II

Total Accepted: 29523 Total
Submissions: 95288 Difficulty: Medium

Note: This is an extension of House
Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This 
time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system 
for these houses remain the same as for those in the previous street.
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.

思路:

聪明的人真多,自己比较笨。想的是,用个flag表示用没用第一个元素,然后在末尾判断。首先是代码非常的繁琐,然后对于[1,1,1,2]这个例子,走到第三个1,都判定0位置元素使用了,然而结果出自不用该0元素。

聪明的解法是,我也不管你用了没用,判断那么多CASE多累。我就走两遍,把你俩分开。一遍有首元素,这样没有末尾元素,长度是length-1;一边是没有首元素,有末尾元素,长度是length-1。

public class Solution {
public int rob(int[] num) {
if (num==null || num.length==0) return 0;
if (num.length==1) return num[0];
int maxToPos[] = new int[num.length];
int max1 = 0;
maxToPos[0] = 0;
maxToPos[1] = num[0];
for (int i=2; i<=maxToPos.length-1; i++){
maxToPos[i] = Math.max(maxToPos[i-1],maxToPos[i-2]+num[i-1]); // 0, 1, 2 <-> dp 1 2 3
}
max1= maxToPos[num.length-1];

maxToPos[1] = num[1];
for (int i=2; i<=maxToPos.length-1; i++){
maxToPos[i] = Math.max(maxToPos[i-1],maxToPos[i-2]+num[i]); // 1, 2, 3 <-> dp 1 2 3
}
return Math.max(max1, maxToPos[num.length-1]);
}
}


337. House Robber III

Total Accepted: 12749 Total
Submissions: 34058 Difficulty: 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:

3
/ \
2   3
\   \
3   1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:

3
/ \
4   5
/ \   \
1   3   1

Maximum amount of money the thief can rob = 4 + 5 = 9.

这题其实挺难的,想了半天都不会。

一开始以为将每个level的点遍历,存到数组同一个level的位置,这样问题就变成了House Robber I。然而 error告诉我只是要求节点不相邻。这就麻烦了。

然而高手就是高手,总是有nice, clean的解。参考这里。最初的思维是说,我要传递max,那我怎么知道子节点使用了没使用子节点的值?高手说:好说,那就传递俩值(int[]),一个代表加上该节点的max值,另外一个代表不要该节点的max值。前者由该点的值+俩子节点不算值得出;后者则由俩子节点各自max之和得出(当前节点不用,所以对子节点是否使用不限制)。

/**
* Definition for a binary tree node.
* public class TreeNode {
*     int val;
*     TreeNode left;
*     TreeNode right;
*     TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int rob(TreeNode root) {
int[] num = dfs(root);
return Math.max(num[0], num[1]);
}
private int[] dfs(TreeNode x) {
if (x == null) return new int[2];
int[] left = dfs(x.left);
int[] right = dfs(x.right);
int[] res = new int[2];
res[0] = left[1] + right[1] + x.val;
res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return res;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode