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;
    }

每一个节点,都对应这个两个结果,就是偷和不偷,而且上面的节点是依赖于下面的节点的,所以考虑使用后续遍历,得到左右孩子的结果,然后再来处理当前的