美文网首页
337. 打家劫舍 III

337. 打家劫舍 III

作者: 最困惑的时候就是能成长的时候 | 来源:发表于2019-07-29 11:17 被阅读0次

    337. 打家劫舍 III

    1.想法:

    从根节点选起,分为两种情况
    1.选择了根,那么左右子节点都不能选择,但是其子节点的节点不受影响.


    image.png

    2.不选择根,其值为选择左边的加上选择右边的.


    image.png
    因为中间一定存在根节点,使得左右之间有界限,那么左右子节点到底选不选,例如2,到底要不要2,这个这个问题就变成了原问题,但是规模减少一
    image.png

    总结:这个过程是一个递归的过程,那么我们用一个标记位来表示这个节点能不能选.可以递归为:
    rob(root)\begin{cases}1.root可选.这几种的max\begin{cases}1.选择root,那么左右都不可选,计算左右的下一代+root.val \\2.不选择root,那么计算左右节点的值 \\\end{cases} \\2.不选择root,那么计算左右节点的值 \end{cases}

    2.代码

    1.没有任何的辅助空间

      public int rob(TreeNode root) {
          //第一个参数是节点,第二个是是否可选
           return myRob(root,true);
        }
    
        private int myRob(TreeNode root, boolean b) {
           //如果为null直接返回0
            if(root == null)return 0;
            //如果可选,那么就选择是否选择root节点
            if(b){
               //从是否选择root节点和不选择root节点中挑出最大的
                return Math.max(myRob(root.left,false)+myRob(root.right,false)+root.val,
                        myRob(root.left,true)+myRob(root.right,true));
            }
            不可选择的时候直接选择左右子节点
            return myRob(root.left,true)+myRob(root.right,true);
        }
    
    image.png

    可以看到时间还是很高的,我们认真分析一下,肯定是递归过程中重复计算的太多了

    2.优化一,优化重复计算

    我们可以明显看到当root节点可选的时候和root节点不可选的时候都做了不选root节点的选项


    image.png

    我们把公共部分提出来.

    public int rob(TreeNode root) {
           return myRob(root,true);
        }
    
        private int myRob(TreeNode root, boolean b) {
           if(root == null)return 0;
          //root可选与不可选的公共部分
            int noChoice = myRob(root.left,true)+myRob(root.right,true);
            if(b){
                return Math.max(myRob(root.left,false)+myRob(root.right,false)+root.val,
                        noChoice);
            }
            return noChoice;
        }
    
    image.png

    总结:有部分优化,但是还是不理想,归根到底,我们在做的时候,对root可选与不可选只是提出一部分,但是当root可选与不可选到了子节点的子节点时,就继续重复了.


    image.png

    3.优化二,优化存储,避免重复计算

    利用Map来存储节点是否被计算,这样会节省计算的时间

     Map<TreeNode,Integer> temp = new HashMap<>();
        public int rob(TreeNode root) {
           return myRob(root,true);
        }
    
        private int myRob(TreeNode root, boolean b) {
            if(root == null)return 0;
             //不选择当前节点
            int noChoice=0,noChoiceLeft=0,noChoiceRight=0,choice=0;
            //如果包含了该节点,直接返回,不包含的话计算后更新
            if(temp.containsKey(root.left)){
                noChoiceLeft = temp.get(root.left);
            }else{
                noChoiceLeft = myRob(root.left,true);
                temp.put(root.left,noChoiceLeft);
            }
            if(temp.containsKey(root.right)){
                noChoiceRight = temp.get(root.right);
            }else{
                noChoiceRight = myRob(root.right,true);
                temp.put(root.right,noChoiceRight);
            }
            noChoice = noChoiceLeft + noChoiceRight;
            //如果可以选择当前节点
            if(b){
                int choiceLeft = myRob(root.left,false);
                int choiceRight = myRob(root.right,false);
                //选择后的结果
                choice = choiceLeft+choiceRight+root.val;
                //比较不选择和选的大小
                return Math.max(choice,noChoice);
            }
            return noChoice;
        }
    
    image.png

    相关文章

      网友评论

          本文标题:337. 打家劫舍 III

          本文链接:https://www.haomeiwen.com/subject/idmvrctx.html