利用动态规划,记dp[i]为走到第i间房屋时所抢的钱数的最大值,对于第i间房,有抢和不抢两种方案,取决于哪种选择获益最大,所以dp[i]=max{dp[i-1],dp[i-2]+nums[i]}.
public class Solution {
// O(n)空间的写法
public int rob1(int[] num) {
if (num.length == 0) return 0;
int[] dp = new int[num.length + 1];
dp[0] = 0;
dp[1] = num[0];
for (int i = 2; i <= num.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + num[i - 1]);
}
return dp[num.length];
}
// O(1)空间的写法
public int rob(int[] num) {
if (num.length == 0) return 0;
int prepre = 0;
int pre = num[0];
for (int i = 1; i < num.length; i++) {
int cur = Math.max(prepre + num[i], pre);
prepre = pre;
pre = cur;
}
return pre;
}
}
对于该题,说明第1间屋子和第n间屋子不能同时抢,所以分开算(1-n-1和2-n),钱数取其中最大的即可 。
public class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) return 0;
if (n == 1) return nums[0];
return Math.max(robBetween(nums, 0, n - 2), robBetween(nums, 1, n - 1));
}
public int robBetween(int[] nums, int start, int end) {
int prepre = 0;
int pre = nums[start];
for (int i = start + 1; i <= end; i++) {
int cur = Math.max(prepre + nums[i], pre);
prepre = pre;
pre = cur;
}
return pre;
}
}
首先可以采用递归思路:
从根节点出发,可以选择偷根节点或者不偷:
- 偷根节点,最大值为:根节点值 + 从左子树出发最大值(不含左子树)+ 从右子树出发最大值(不含右子树)
- 不偷根节点,最大值为:从左子树出发最大值(含左子树)+ 从右子树出发最大值(含右子树)
最后比较两者,取较大值。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int rob(TreeNode root) {
if (root == null) return 0;
int left = root.left != null ? rob(root.left.left) + rob(root.left.right) : 0;
int right = root.right != null ? rob(root.right.left) + rob(root.right.right) : 0;
return Math.max(root.val + left + right, rob(root.left) + rob(root.right));
}
}
此外,还可以采用动态规划:
这里设置一个返回数字res,其中res[0]表示抢劫当前节点, res[1]不抢劫当前节点,直接DFS递归遍历即可实现。
/*class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}*/
/*
* 这其实也是DP的解决方法之一,
* */
class Solution
{
public int rob(TreeNode root)
{
if(root==null)
return 0;
int []res=getRes(root);
return Math.max(res[0], res[1]);
}
/*
* res[0]表示抢劫当前节点的记录的最大值
* res[1]表示不抢劫当前的结点的记录的最大值
* */
public int[] getRes(TreeNode root)
{
int[] res=new int[2];
if(root==null)
return res;
else
{
int[] left=getRes(root.left);
int[] right=getRes(root.right);
//抢劫当前节点,然后不抢劫其子节点
res[0]=root.val + left[1] + right[1];
//不抢劫当前节点,然后可以抢劫或者不抢劫其子节点
res[1]=Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return res;
}
}
}