程式碼隨想錄 | 二叉樹

226. 翻轉二叉樹

給你一棵二叉樹的根節點 root ,翻轉這棵二叉樹,並返回其根節點。

輸入:root = [4,2,7,1,3,6,9]
輸出:[4,7,2,9,6,3,1]

ψ(`∇´)ψ 我的思路

  • 還是用了層序遍歷的方法,在該結點左右孩子入棧之後,互換左右指針
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        Queue<TreeNode> que = new LinkedList<>();
        if (root == null) {
            return root;
        }
        que.add(root);
        while (!que.isEmpty()) {
            int size = que.size();
            while (size > 0) {
                TreeNode node = que.poll();
                TreeNode tmp = new TreeNode();
                if (node.right != null && node.left != null) {
                    //左右孩子都不空,右孩子、左孩子加入隊列並交換
                    que.add(node.right);
                    que.add(node.left);
                    tmp = node.right;
                    node.right = node.left;
                    node.left = tmp;
                } else if (node.right==null&&node.left!=null ) {
                    que.add(node.left);
                    node.right=node.left;
                    node.left=null;
                } else if(node.left==null&&node.right!=null){
                    que.add(node.right);
                    node.left=node.right;
                    node.right=null;
                }
                size--;
            }
        }
        return root;
    }
}
  • 下面是遞歸的做法:
/**
 * 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;
 *     }
 * }
 */
class Solution {
   public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        //先序遍歷
        swapChildren(root);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

101. 對稱二叉樹

給你一個二叉樹的根節點 root , 檢查它是否軸對稱。

輸入:root = [1,2,2,3,4,4,3]
輸出:true

ψ(`∇´)ψ 我的思路

  • 層序遍歷每一層二叉樹,每一層結點的值放入鏈表,判斷鏈表(除第一層外)是否對稱
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> que = new LinkedList<>();
        que.add(root);
        while (!que.isEmpty()){
            int size = que.size();
            List<Integer> list = new ArrayList<>();
            while (size>0){
                TreeNode node = que.poll();
                list.add(node.val);//加入鏈表
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }
            //判斷list是不是對稱列表
            if(list.size()>1){
                Collections.reverse(list.subList(0,list.size()/2));
                if(!list.subList(0,list.size()/2).equals(list.subList(list.size()/2,list.size()))){
                    return false;
                }
            }
        }
        return true;
    }
}
  • 上面的程式碼並不能判斷下面這種情況:

    輸入:root = [1,2,2,null,3,null,3]
    輸出:false

  • 因為只把不空的結點加入到鏈表,所以上述情況的鏈表是這樣的:[1][2,2][3,3],我想著把null也加入到鏈表裡。不行(x_x),那樣的話就沒辦法控制臨界條件了。

  • 下面是程式碼隨想錄的遞歸做法:比較根結點的左右子樹是否對稱

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        boolean res = comparable(root.left, root.right);
        return res;

    }
    public static boolean comparable(TreeNode left, TreeNode right){
        if(left==null&&right!=null){return false;}
        else if(right==null&&left!=null){return false;}
        else if(right==null&&left==null){return true;}
        else if(right.val!= left.val){return false;}
        boolean a = comparable(left.left, right.right);//比較外側結點
        boolean b = comparable(left.right, right.left);//比較內測結點
        boolean res = a && b;
        return  res;
    }
}
  • 感覺遞歸的做法要好理解很多,再寫兩道類似的題目練一下遞歸

100. 相同的樹

給你兩棵二叉樹的根節點 p 和 q ,編寫一個函數來檢驗這兩棵樹是否相同。
如果兩個樹在結構上相同,並且節點具有相同的值,則認為它們是相同的。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
       //if(p==null&&q==null){return false;}
        return comparable(p,q);
    }

    public boolean comparable(TreeNode p,TreeNode q){
        if(p!=null&&q==null){return false;}
        else if(p==null&&q==null){return true;}
        else if(p==null&&q!=null){return false;}
        else if(p.val!=q.val){return false;}
        boolean a = comparable(p.left,q.left);
        boolean b = comparable(p.right,q.right);
        return a && b;
    }
}

572. 另一棵樹的子樹

給你兩棵二叉樹 root 和 subRoot 。檢驗 root 中是否包含和 subRoot 具有相同結構和節點值的子樹。如果存在,返回 true ;否則,返回 false 。
二叉樹 tree 的一棵子樹包括 tree 的某個節點和這個節點的所有後代節點。tree 也可以看做它自身的一棵子樹。

/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        //前序遍歷root
        List<TreeNode> nodes = new ArrayList<>();
        preorder(root,nodes);
        for (TreeNode node : nodes) {
            //此時nodes裡面是root中的所有結點
            if(comparable(node, subRoot)){
                return true;
            }
        }
        return false;
    }
    public void preorder(TreeNode root, List<TreeNode> nodes){
        if(root==null){return ;}
        nodes.add(root);
        preorder(root.left,nodes);
        preorder(root.right,nodes);
    }
    
    public boolean comparable(TreeNode left,TreeNode right){
        if(left==null&&right==null){return true;}
        else if(left!=null&&right==null){return false;}
        else if(left==null&&right!=null){return false;}
        else if(left.val!= right.val){return false;}
        boolean a = comparable(left.left, right.left);
        boolean b = comparable(left.right, right.right);
        return a && b;
    }
}

104. 二叉樹的最大深度

  • 這題昨天用層序遍歷寫過,下面是遞歸的實現:
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        //這裡用根結點的高度表示二叉樹的最大深度
        if(root==null){return 0;}
        int leftDepth = maxDepth(root.left);//左孩子的高度
        int rightDepth = maxDepth(root.right);//右孩子的高度
        return Math.max(leftDepth,rightDepth)+1;//當前結點的高度(左孩子的高度,右孩子的高度的最大值+1)
        //後序遍歷
    }
}
  • 感覺遞歸還是不太好理解

559. N 叉樹的最大深度

給定一個 N 叉樹,找到其最大深度。
最大深度是指從根節點到最遠葉子節點的最長路徑上的節點總數。
N 叉樹輸入按層序遍歷序列化表示,每組子節點由空值分隔

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public int maxDepth(Node root) {
        if(root==null){return 0;}
        List<Node> children = root.children;//當前結點的孩子們
        int max = 0;
        for (Node child : children) {
            int depth = maxDepth(child);
            max = Math.max(depth,max);
        }
        return max+1;
    }
}
  • 擴展成n叉樹,和二叉樹區別不大,就是孩子數不確定,用for循環遍歷求孩子的高度就好

111. 二叉樹的最小深度

給定一個二叉樹,找出其最小深度。
最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。
說明:葉子節點是指沒有子節點的節點。

ψ(`∇´)ψ 我的思路

  • 稍微改了二叉樹最大深度的程式碼,
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){return 0;}//空的結點是第0層(也是遞歸出口)
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        return Math.min(leftDepth,rightDepth)+1;
    }
}
  • 程式碼在運行下圖例子時返回1

題目中說的是:最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。

  • 在上述程式碼中,只有一個孩子的結點會被誤以為是葉子結點,返回該結點的高度。改進後程式碼如下:
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){return 0;}//空的結點是第0層(也是遞歸出口)
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        if(root.left==null){return rightDepth+1;}//如果左子樹為空,返回右子樹的高度+1
        else if(root.right==null){return leftDepth+1;}//如果右子樹為空,返回左子樹的高度+1
        return Math.min(leftDepth,rightDepth)+1;
    }
}

222. 完全二叉樹的節點個數

完全二叉樹 的根節點 root ,求出該樹的節點個數。
完全二叉樹 的定義如下:在完全二叉樹中,除了最底層節點可能沒填滿外,其餘每層節點數都達到最大值,並且最下面一層的節點都集中在該層最左邊的若干位置。若最底層為第 h 層,則該層包含 1~ 2h 個節點。

ψ(`∇´)ψ 我的思路

  • 層序遍歷,每彈出一個數count++
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int countNodes(TreeNode root) {
        Queue<TreeNode> que = new LinkedList<>();
        if(root==null){return 0;}
        int count = 0;
        que.add(root);
        while (!que.isEmpty()){
            int size = que.size();
            while (size>0){
                count++;
                TreeNode node = que.poll();
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }
        }
        return count;
    }
}
  • 不知道是不是昨天層序遍歷做多了,我現在拿到題想的都是層序遍歷,遞歸好難想啊🤯
class Solution {
    // 還是展示遞歸解法(後序遍歷)
    public int countNodes(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
  • 離譜離譜,就這麼幾行

110. 平衡二叉樹

給定一個二叉樹,判斷它是否是高度平衡的二叉樹。
本題中,一棵高度平衡二叉樹定義為:
一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1 。

ψ(`∇´)ψ 我的思路

  • 求出根結點左右子樹的最大高度,相減取絕對值不超過1即為平衡二叉樹
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null){return true;}
        int leftHeight = maxHeight(root.left);
        int rightHeight = maxHeight(root.right);
        if(Math.abs(leftHeight-rightHeight)<=1){
            return true;
        } else{return false;}
    }

    public int maxHeight(TreeNode root){
        if(root==null){return 0;}
        return Math.max(maxHeight(root.left),maxHeight(root.right))+1;
    }
}

  • 按我的思路,這就是個平衡二叉樹,仔細讀題後發現:

一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1 。

  • 應該在外面再套一個循環,但是那樣程式碼就太複雜了。下面是程式碼隨想錄的解法:
  • 先來區分一下高度和深度(高度用後序遍歷,深度用前序遍歷)

    上面的題目中有求二叉樹最大深度的題目,用到後序遍歷,是因為求二叉樹的最大深度就是求根結點的高度
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        //後序遍歷
        int height = getHeight(root);
        if(height==-1){return false;}
        else return true;
    }

   public int getHeight(TreeNode root){
        if(root==null){
            return 0;//null結點高度為0
        }
       int leftHeight = getHeight(root.left);//左子樹的高度
       if(leftHeight==-1){return -1;}
       int rightHeight = getHeight(root.right);//右子樹的高度
       if(rightHeight==-1){return -1;}
       if(Math.abs(leftHeight-rightHeight)>1){return -1;}//當前結點左右子樹高度差>1
       return 1+Math.max(leftHeight,rightHeight);//返回當前結點的高度
    }
}
  • 遞歸,遞歸,又是你!!!

257. 二叉樹的所有路徑

給你一個二叉樹的根節點 root ,按 任意順序 ,返回所有從根節點到葉子節點的路徑。
葉子節點 是指沒有子節點的節點。

  • 這題用到了回溯,不懂回溯,偷了張圖大概看一下
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();//結果列表
        if(root==null){return res;}
        List<Integer> path = new ArrayList<Integer>();//路徑列表(存放經過結點的值)
        postOrder(root,path,res);
        return res;
    }

    public void postOrder(TreeNode node,List<Integer> path,List<String> res){
        path.add(node.val);//每一個結點都加在路徑裡面
        if(node.left==null&&node.right==null){//如果node沒孩子(葉子節點)
            //就可以把path轉換成String加到res中啦
            StringBuilder sb = new StringBuilder();
            for (Integer i : path) {
                sb.append(i+"->");
            }
            String s = sb.toString();
            s = s.substring(0,s.length()-2);//把最後一個->去掉
            res.add(s);
        }
       if (node.left != null) {
            postOrder(node.left, path, res);
            path.remove(path.size()-1);//回溯
        }
        if (node.right != null) {
            postOrder(node.right, path, res);
            path.remove(path.size()-1);//回溯
        }
    }
}
  • 這題挺好,標記。

404. 左葉子之和

給定二叉樹的根節點 root ,返回所有左葉子之和。

  • 這題的突破點是找左葉子的定義:當一個結點的左孩子不空(無所謂右孩子),且左孩子沒孩子,即為左葉子。
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root==null){
            return 0;
        }
        int midValue = 0;//存儲當前結點的左孩子的值
        if(root.left!=null&&root.left.left==null&&root.left.right==null){
            midValue = root.left.val;//如果root.left滿足左葉子的條件
        }
        int leftValue = sumOfLeftLeaves(root.left);
        int rightValue = sumOfLeftLeaves(root.right);
        return midValue+leftValue+rightValue;//返回當前結點的值,加上左右孩子的葉子結點數
    }
}
  • 遞歸真的是不好想啊,感覺我現在的水平只能是看懂

513. 找樹左下角的值

給定一個二叉樹的 根節點 root,請找出該二叉樹的 最底層 最左邊 節點的值。
假設二叉樹中至少有一個節點。

ψ(`∇´)ψ 我的思路

  • 層序遍歷到最後一層,第一個彈出的值即為所求
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public int findBottomLeftValue(TreeNode root) {
         Queue<TreeNode> que = new LinkedList<>();
        List<Integer> list = null;
        que.add(root);
        while (!que.isEmpty()){//控制層數
            list = new ArrayList<>();
            int size = que.size();
            while (size>0){//控制每層的元素個數
                TreeNode node = que.poll();
                list.add(node.val);
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                if(size==1){       
                }
                size--;
            }  
        }
        return list.get(0);//因為鏈表每層都刷新,所以此時鏈表記錄的是最後一層的結點
    }
}
  • hhh,只要可以用層序遍歷,我就是小神仙🎈

112. 路徑總和

給你二叉樹的根節點 root 和一個表示目標和的整數 targetSum 。判斷該樹中是否存在 根節點到葉子節點 的路徑,這條路徑上所有節點值相加等於目標和 targetSum 。如果存在,返回 true ;否則,返回 false 。
葉子節點 是指沒有子節點的節點。

  • 感覺和上面的二叉樹的所有路徑很像,就改了一下上面的程式碼。第一遍的時候是自己寫的,沒有寫出來。
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        List<Integer> res = new ArrayList<>();//用來存放所有路徑的和
        if(root==null){return false;}
        List<Integer> path = new ArrayList<Integer>();//用來存放經過結點的值
        postOrder(root,path,res);
        if(res.contains(targetSum)){return true;}
        else return false;
    }

    public void postOrder(TreeNode node,List<Integer> path,List<Integer> res){
        path.add(node.val);//每一個結點的值都加在路徑裡面
        if(node.left==null&&node.right==null){//如果node沒孩子(葉子節點)
            int sum = 0;
            for (Integer i : path) {
                sum += i;
            }
            res.add(sum); //求出當前路徑的總和加到res中
        }
        if (node.left != null) {
            postOrder(node.left, path, res);
            path.remove(path.size()-1);//回溯
        }
        if (node.right != null) {
            postOrder(node.right, path, res);
            path.remove(path.size()-1);//回溯
        }
    }
}

113. 路徑總和 II

給你二叉樹的根節點 root 和一個整數目標和 targetSum ,找出所有 從根節點到葉子節點 路徑總和等於給定目標和的路徑。
葉子節點 是指沒有子節點的節點。

ψ(`∇´)ψ 我的思路

  • 還是路徑的問題,我就按路徑的模板寫了一下,但是在debug的時候發現res會隨著path的改變而改變。活見鬼👻,我明明已經把path加到res里了。
/**
 * 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;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();//結果列表
        List<Integer> path = new ArrayList<>();//路徑列表
        if(root==null){return res;}
        path(root,path,res,targetSum);
        return res;
    }

    void path(TreeNode node,List<Integer> path,List<List<Integer>> res,int targetSum){
        path.add(node.val);
        if(node.left==null&&node.right==null){//到達了葉子結點
            int sum = 0;
            for (Integer i : path) {
                sum+=i;
            }
            if(sum==targetSum){res.add(path);}
        }
       if (node.left != null) {
            path(node.left, path, res, targetSum);
            path.remove(path.size()-1);//回溯
        }
        if (node.right != null) {
            path(node.right, path, res, targetSum);
            path.remove(path.size()-1);//回溯
        }
    }
}
  • 但仔細一想應該是遞歸的問題,我找不到解決的方法,看了題解後發現其實就是一行程式碼
 if(sum==targetSum){ res.add(new ArrayList<>(path));}
  • 活見鬼👻,剛開始看的時候我就不相信這是java的語法,我就沒見過泛型後面的小括弧裡面放東西😟,但是運行通過。網上也找不到靠譜的解釋,我猜是新建了一個與path相同類型的鏈表把path裝了進來,這樣我再debug,res就不會隨著遞歸變化了。

❗標記,標記,這一題不太會

106. 從中序與後序遍歷序列構造二叉樹

給定兩個整數數組 inorder 和 postorder ,其中 inorder 是二叉樹的中序遍歷, postorder 是同一棵樹的後序遍歷,請你構造並返回這顆 二叉樹 。

確認過眼神,是我寫不出來的題目🙂

  • 思路是不難理解的,偷個圖展示一下

    步驟:
  1. 判斷後序數組是否為空
  2. 取後序數組的最後一個值的下標切割中序數組,把中序數組切割成左中序和右中序
  3. 用兩個區間的長度去切割後序數組,得到左後序和右後序
  4. 遞歸(左中序,左後序),遞歸(右中序,右後序)
/**
 * 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;
 *     }
 * }
 */
class Solution {
    Map<Integer, Integer> map;  // 方便根據數值查找位置
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) { // 用map保存中序序列的數值對應位置
            map.put(inorder[i], i);
        }
        return findNode(inorder,  0, inorder.length, postorder,0, postorder.length);  // 前閉後開
    }
    
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {
        // 參數里的範圍都是前閉後開
        if (inBegin >= inEnd || postBegin >= postEnd) {  // 不滿足左閉右開,說明沒有元素,返回空樹
            return null;
        }
        int rootIndex = map.get(postorder[postEnd - 1]);  // 找到後序遍歷的最後一個元素在中序遍歷中的位置
        TreeNode root = new TreeNode(inorder[rootIndex]);  // 構造結點
        int lenOfLeft = rootIndex - inBegin;  // 保存中序左子樹個數,用來確定後序數列的個數
        root.left = findNode(inorder, inBegin, rootIndex, postorder, postBegin, postBegin + lenOfLeft);
        root.right = findNode(inorder, rootIndex + 1, inEnd, postorder, postBegin + lenOfLeft, postEnd - 1);
        return root;
    }
}
  • ❗ 標記,標記,這題不是自己寫的

105. 從前序與中序遍歷序列構造二叉樹

給定兩個整數數組 preorder 和 inorder ,其中 preorder 是二叉樹的先序遍歷, inorder 是同一棵樹的中序遍歷,請構造二叉樹並返回其根節點。

  • 與上一題類似,改了一下上一題的程式碼
/**
 * 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;
 *     }
 * }
 */
class Solution {
    Map<Integer, Integer> map;  // 方便根據數值查找位置
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) { // 用map保存中序序列的數值對應位置
            map.put(inorder[i], i);
        }
        return findNode(inorder,  0, inorder.length, preorder,0, preorder.length);  // 前閉後開
    }
    
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] preorder, int preBegin, int preEnd) {
        // 參數里的範圍都是前閉後開
        if (inBegin >= inEnd || preBegin >= preEnd) {  // 不滿足左閉右開,說明沒有元素,返回空樹
            return null;
        }
        int rootIndex = map.get(preorder[preBegin]);  // 找到前序遍歷的最後一個元素在中序遍歷中的位置
        TreeNode root = new TreeNode(inorder[rootIndex]);  // 構造結點
        int lenOfLeft = rootIndex - inBegin;  // 保存中序左子樹個數,用來確定前序數列的個數
        root.left = findNode(inorder, inBegin, rootIndex, preorder, preBegin+1, preBegin + lenOfLeft+1);
        root.right = findNode(inorder, rootIndex + 1, inEnd, preorder, preBegin + lenOfLeft+1, preEnd);
        return root;
    }
}
  • 太殘忍了,太殘忍了,最後這兩題,就是在屠殺我的腦細胞💀,不知道看多少集海綿寶寶才能養回來

總結

  • 今天的題比昨天的題要好,每一道題都很有代表性😀

  • 翻轉二叉樹:交換結點指向左右孩子的指針

  • 對稱二叉樹:以根結點所在豎直線為對稱軸,先比較外側結點,後比較內側結點(相同的樹,另一棵樹的子樹類似)(有點像雙指針

  • 二叉樹的最大深度:求二叉樹的最大深度就是求根結點的高度,求高度用後序遍歷,當前結點的高度是左右孩子高度的最大值+1(N叉樹的最大深度類似)

  • 二叉樹的最小深度:如果左子樹為空,當前結點的高度為右子樹的高度+1;如果右子樹為空,當前結點的高度為左子樹的高度+1,畫個圖你就知道啦🤡

  • 完全二叉樹的結點個數:基礎的遍歷題

  • 平衡二叉樹:求高度的題,要用後序遍歷

  • 二叉樹的所有路徑:求路徑的題,要用到回溯,需要什麼條件就往遞歸方法中加參數就可

  • 左葉子之和:關鍵是判斷左葉子

  • 找樹左下角的值:層序遍歷

  • 路徑總和:改路徑題的模板(其實還是有點迷的,尤其是遞歸方法帶參數,好傢夥,那是一個千變萬化,根本分析不出來😵)

  • 從中/前序後序遍歷序列構造二叉樹,重點在區間的劃分

  • 遇到問題總是先想層序遍歷,但是感覺遞歸才是正統解法,要好好掌握遞歸才行

  • 做了一天的二叉樹,現在感覺我就是個二叉樹🤐

Tags: