dsds
//首先想到动态规划,如果只有一间房,那么只能偷这一间房的,如果有两间房,则怎样,以此类推
//边界条件:dp[0]=0,dp[1]=nums[0],dp[2]=max(nums[0],nums[1])以此到dp[n]间房
//转移方程:dp[n] = max[dp[[n-2]+nums[i],dp[n-1];
class Solution {
public int rob(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
dp[0] = nums[0];
dp[1] = Math.max(nums[1], nums[0]);
for(int i = 2 ; i < len ; i++){
dp[i] = Math.max(dp[i-2] + nums[i] , dp[i-1]);
}
return dp[len-1];
}
}
dsds
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//第一种就是暴力递归,看解析中我们想成爷爷,两个孩子,四个孙子来说明问题
//偷钱有两种偷法:爷爷偷+4个孙子偷,只有2个儿子偷
//则单个节点的计算 : 爷爷和孙子偷的:int money1 = root.val+rob(root.left.left)+rob(root.left.right)+rob(root.right.left)+rob(root.left.right),儿子偷的:int money2 = rob(root.left) + rob(root.right);选择钱最多的方案int result = Math.max(money1,money2)
// 1、虽然能解出来,但是递归时间复杂度太高,所以我们进行优化
// class Solution {
// public int rob(TreeNode root) {
// //递归头
// if(root == null){
// return 0;
// }
// int money = root.val;
// if(root.left!=null){
// money += rob(root.left.left) + rob(root.left.right);
// }
// if(root.right!=null){
// money += rob(root.right.left) + rob(root.right.right);
// }
// return Math.max( money , rob(root.left) + rob(root.right));
// }
// }
// 2、对第一种方法进行优化,有一个重复的子问题:当爷爷算钱的时候,孙子的也会算,那么当到了爸爸节点的时候,依旧要算孙子的
// 解决方法:之前的问题都是使用数组解决的,现在把每次计算的结果都存起来,下次如果再来计算,就从缓存中取,不再计算了,这样就保证每个数只计算一次,由于二叉树不适合拿数组当缓存,我们这次使用哈希表来存储结果,TreeNode 当做 key,能偷的钱当做 value
// class Solution {
// public int rob(TreeNode root ) {
// //通过哈希表进行存储每个节点的最大值
// Map<TreeNode , Integer> moneyMaxPerNode = new HashMap<>();
// return robInternal(root , moneyMaxPerNode);
// }
// public int robInternal(TreeNode root , Map<TreeNode , Integer> moneyMaxPerNode){
// //递归头
// if(root == null){
// return 0;
// }
// //避免多次存入,相当于对方法一的剪枝
// if(moneyMaxPerNode.containsKey(root)){
// return moneyMaxPerNode.get(root);
// }
// //当前值
// int money = root.val;
// //和孙子的值
// if(root.left!=null){
// money += (robInternal( root.left.left, moneyMaxPerNode)+ robInternal(root.left.right , moneyMaxPerNode));
// }
// if(root.right != null){
// money += (robInternal(root.right.left , moneyMaxPerNode) + robInternal(root.right.right , moneyMaxPerNode));
// }
// //爷爷+孙子 和 儿子的值的比较
// money = Math.max(money , robInternal(root.left,moneyMaxPerNode) + robInternal(root.right , moneyMaxPerNode));
// //存入最大值
// moneyMaxPerNode.put(root , money);
// return money;
// }
// }
// //方法3:虽然我们通过一个哈希表进行了优化,但是也有性能的损耗,换一种方法来表示:使用一个大小为 2 的数组来表示 int[] res = new int[2] 0 代表不偷,1 代表偷
// //1、当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
// //2、当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数
// //对应公式:
// //root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val
// //root[0] = Math.max(rob(root.left)[0],rob(root.left)[1]) + Math.max(rob(root.right)[0],rob(root.right)[1])
class Solution {
public int rob(TreeNode root) {
//分成两种情况,分别放到数组中,然后取其中的最大值
int[] maxMoney = robInternal(root);
return Math.max(maxMoney[0] , maxMoney[1]);
}
public int[] robInternal(TreeNode root){
if(root == null){
return new int[2];
}
int[] choiceArray = new int[2];
int[] left = robInternal(root.left);
int[] right = robInternal(root.right);
choiceArray[0] = Math.max(left[0], left[1]) + Math.max(right[0] ,right[1]);
choiceArray[1] = left[0] + right[0] + root.val;
return choiceArray;
}
}