Leetcode 198
最初的就是考虑一维的dp,代码实现如下
class Solution {
public static int rob(int[] nums) {
if(nums==null||nums.length==0) return 0;
if(nums.length<=2) return nums.length==1?nums[0]:Math.max(nums[0],nums[1]);
int[] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[1],nums[0]);
for(int i=2;i<nums.length;i++)
{
dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[nums.length-1];
}
}leetcode 213 围成一圈的打家劫舍
对于这种情况就需要比较三种情况的大小,但是第一种情况是不需要比较的,因为情况2和情况3都包括了第一种情况,因为,如果不包括两端,但是仍是最大的话,情况2和情况3都是涵盖
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 Math.max(nums[0],nums[1]);
if(nums.length==3) return Math.max(nums[0],Math.max(nums[1],nums[2]));
int res=rob1(nums,0,nums.length-2);
int res2=rob1(nums,1,nums.length-1);
return Math.max(res,res2);
}
public int rob1(int[] nums,int start,int end)
{
int[] dp=new int[nums.length];
dp[start]=nums[start];
dp[start+1]=Math.max(nums[start],nums[start+1]);
for(int i=start+2;i<=end;i++)
{
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[end];
}
}二叉树的打家劫舍
对于递归的方法就是脱离了上面两种动态规划的规则
暴力
public int rob(TreeNode root)
{
if(root==null) return 0;
int money=root.val;
int money2=0;
if(root.left!=null)
{
money+=rob(root.left.left)+rob(root.left.right);
money2+=rob(root.left);
}
if(root.right!=null)
{
money+=rob(root.right.left)+rob(root.right.right);
money2+=rob(root.right);
}
return Math.max(money,money2);
return robWithMemory(root,new HashMap<TreeNode,Integer>());
}带记忆的递归
public int robWithMemory(TreeNode root,HashMap<TreeNode,Integer> map)
{
if(root==null) return 0;
if(map.containsKey(root)) return map.get(root);
int money=root.val;
int money2=0;
if(root.left!=null)
{
money+=robWithMemory(root.left.left,map)+robWithMemory(root.left.right,map);
money2+=robWithMemory(root.left,map);
}
if(root.right!=null)
{
money+=robWithMemory(root.right.left,map)+robWithMemory(root.right.right,map);
money2+=robWithMemory(root.right,map);
}
int curRes=Math.max(money,money2);
map.put(root,curRes);
return Math.max(money,money2);
}需要注意的点,就是设置map和取map的两个位置,我本来想着在robWithMemory(root.left.left,map)的这些位置都加上取map的操作,后来看到解析,直接
if(map.containsKey(root)) return map.get(root);即可,这儿是需要注意的
时间最快的递归方式
和二叉树有关的,我们就可以想到二叉树的遍历。
当前这道题其实已经和前面两道题都已经脱离开了,对于这一道题来说,我们可以考虑当前位置要不要偷两种情况。
这一道题可以考虑改写二叉树的后序遍历
public static int rob3(TreeNode root)
{
if(root==null) return 0;
int[] f = f(root);
return Math.max(f[0],f[1]);
}
public static int[] f(TreeNode root)
{
if(root==null) return new int[]{0,0};
//res[0]当前位置不偷
//res[1]当前位置要偷
int[] res=new int[2];
int[] left = f(root.left);
int[] right=f(root.right);
res[0]=Math.max(left[0],left[1])+Math.max(right[0],right[1]);
res[1]=root.val+left[0]+right[0];
return res;
}每一个节点,都对应这个两个结果,就是偷和不偷,而且上面的节点是依赖于下面的节点的,所以考虑使用后续遍历,得到左右孩子的结果,然后再来处理当前的

京公网安备 11010502036488号