程式碼隨想錄 | 二叉樹的遍歷

二叉樹的遞歸遍歷

遞歸的三要素

1.遞歸函數的參數和返回值

2.遞歸出口

3.單層遞歸的邏輯

144. 二叉樹的前序遍歷

給你二叉樹的根節點 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<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        preoder(root,result);
        return result;
    }
    public void preoder(TreeNode node,List<Integer> result){
        if (node==null){
            return;
        }
        result.add(node.val);//前序遍歷:中、左、右
        preoder(node.left,result);
        preoder(node.right,result);
    }
}

94. 二叉樹的中序遍歷

給定一個二叉樹的根節點 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<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList();
        inorder(root,result);
        return result;
    }
    public void inorder(TreeNode node, List<Integer> result){
        if(node==null){
            return;
        }
        inorder(node.left,result);//中序遍歷:左、中、右
        result.add(node.val);
        inorder(node.right,result);
    }
}

145. 二叉樹的後序遍歷

給你一棵二叉樹的根節點 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<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList();
        postorder(root,result);
        return result;
    }
    public void postorder(TreeNode node,List<Integer> result){
        if(node==null){
            return;
        }
        postorder(node.left,result);//後序遍歷:左、右、中
        postorder(node.right,result);
        result.add(node.val);
    }
}

二叉樹的迭代遍歷

用棧操作,遞歸也是用棧實現的嘛🙂

144. 二叉樹的前序遍歷

給你二叉樹的根節點 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<Integer> preorderTraversal(TreeNode root) {
         List<Integer> result = new ArrayList<>();//結果列表
        Stack<TreeNode> stack = new Stack<>();
        if(root==null){
            return result;
        }
        stack.push(root);//先把根節點加到棧中去
        while (!stack.empty()){
            TreeNode node = stack.pop();//從棧中彈出一個結點來進行操作
            result.add(node.val);//彈出的元素加到結果列表中
            if(node.right!=null){
                stack.push(node.right);//右孩子不空就進棧
            }
            if(node.left!=null){
                stack.push(node.left);//左孩子不空就進棧
            }
        }
        return result;
    }
}
  • 妙蛙種子吃了妙脆角,妙到家啦

145. 二叉樹的後序遍歷

給你一棵二叉樹的根節點 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<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();//結果列表
        Stack<TreeNode> stack = new Stack<>();
        if(root==null){
            return result;
        }
        stack.push(root);//先把根節點加到棧中去
        while (!stack.empty()){
            TreeNode node = stack.pop();//從棧中彈出一個結點來進行操作
            result.add(node.val);//彈出的元素加到結果列表中
            if(node.left!=null){
                stack.push(node.left);//左孩子不空就進棧
            }
            if(node.right!=null){
                stack.push(node.right);//右孩子不空就進棧
            }
        }
       Collections.reverse(result);
        return result;
    }
}

Collections.reverse(result) 鏈表反轉

  • 這題和前序遍歷十分相似,就是入棧順序不一樣,畫圖找一下順序,改前序遍歷的程式碼就可啦

94. 二叉樹的中序遍歷

給定一個二叉樹的根節點 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<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();//結果列表
        Stack<TreeNode> stack = new Stack<>();
        if(root==null){
            return result;
        }
        TreeNode cur = root;//取到根結點
        while (cur != null || !stack.isEmpty()){
            if (cur != null){
                stack.push(cur);//放入棧中
                cur = cur.left;//把當前結點的左孩子賦給當前結點
            }else{
                cur = stack.pop();//彈出棧中的結點
                result.add(cur.val);//放入結果集中
                cur = cur.right;//把當前結點的右孩子賦給當前結點(左邊已經遍歷完了,上一步也把中間放入結果集中,該右邊了)
            }
        }
        return result;
    }
}

二叉樹的層序遍歷

也就是廣度優先遍歷啦

102.二叉樹的層序遍歷

給你二叉樹的根節點 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<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();//外層鏈表
        Queue<TreeNode> que = new LinkedList<>();//新建一個隊列
        if (root == null) {
            return res;
        }
        que.add(root);//把根節點放入隊列
        while (!que.isEmpty()){
            //當隊列不為空時
            ArrayList<Integer> item = new ArrayList<>();//內層鏈表
            int size = que.size();//隊列的大小
            while (size>0){
                TreeNode node = que.poll();//彈出當前結點
                if(node.left!=null){que.add(node.left);}//把當前結點的左孩子加進去(如果有的話)
                if(node.right!=null){que.add(node.right);}//把當前結點的右孩子加進去(如果有的話)
                item.add(node.val);//當前結點加到鏈表
                size--;
            }
            res.add(item);//內層鏈表加入到外層鏈表中
        }
        return res;
    }
}

下面是一堆層序遍歷的題

107. 二叉樹的層序遍歷 II

給你二叉樹的根節點 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<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();//外層鏈表
        Queue<TreeNode> que = new LinkedList<TreeNode>();//隊列
        if(root==null)return res;
        que.add(root);//把根結點放入隊列
        while (!que.isEmpty()){
            List<Integer> item = new ArrayList<>();
            int size = que.size();
            while (size > 0) {
                TreeNode node = que.poll();//隊列中彈出一個結點
                item.add(node.val);
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }
            res.add(item);
        }
        Collections.reverse(res);
        return res;
    }
}

199. 二叉樹的右視圖

給定一個二叉樹的 根節點 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<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Queue<TreeNode> que = new LinkedList<>();
        if(root==null)return res;
        que.add(root);//根結點不為空,放入隊列
        while (!que.isEmpty()){
            List<Integer> item = new ArrayList<>();
            int size = que.size();
            while (size>0){
                TreeNode node = que.poll();
                item.add(node.val);
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }
            Integer i = item.get(item.size() - 1);
            res.add(i);
        }
        return res;
    }
}

637. 二叉樹的層平均值

給定一個非空二叉樹的根節點 root , 以數組的形式返回每一層節點的平均值。與實際答案相差 10-5 以內的答案可以被接受。

/**
 * 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<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new ArrayList<>();
        Queue<TreeNode> que = new LinkedList<>();
        if(root==null)return res;
        que.add(root);
        while (!que.isEmpty()){
            int size = que.size();
            double x = 0;
            double sum = 0;
            int count = size;
            while (size>0){
                TreeNode node = que.poll();
                sum += node.val;
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }        
            x = sum/count;
            res.add(x);
        }
        return res;
    }
}

429. 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 List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> res = new ArrayList<>();//外層鏈表
        Queue<Node> que = new LinkedList<>();//新建一個隊列
        if (root == null) {
            return res;
        }
        que.add(root);//把根節點放入隊列
        while (!que.isEmpty()){
            //當隊列不為空時
            ArrayList<Integer> item = new ArrayList<>();//內層鏈表
            int size = que.size();//隊列的大小
            while (size>0){
                Node node = que.poll();//彈出當前結點
                //當前結點加到鏈表
                if(node.children!=null){
                    for (Node child : node.children) {
                        que.add(child);
                    }
                }
                item.add(node.val);
                size--;
            }
            res.add(item);//內層鏈表加入到外層鏈表中
        }
        return res;
    }
}
  • 添加子結點到隊列的操作有點不一樣

515. 在每個樹行中找最大值

給定一棵二叉樹的根節點 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<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Queue<TreeNode> que = new LinkedList<>();
        if(root==null){
            return res;
        }
        que.add(root);
        while(!que.isEmpty()){
            int size = que.size();
            int x = Integer.MIN_VALUE;
            while(size>0){
                TreeNode node = que.poll();
                x = node.val>x ? node.val : x;
                if(node.left!=null){que.add(node.left);}
                if(node.right!=null){que.add(node.right);}
                size--;
            }
            res.add(x);
        }
        return res;
    }
}

116. 填充每個節點的下一個右側節點指針

給定一個 完美二叉樹 ,其所有葉子節點都在同一層,每個父節點都有兩個子節點。二叉樹定義如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指針,讓這個指針指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指針設置為 NULL。
初始狀態下,所有 next 指針都被設置為 NULL。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

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

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        Queue<Node> que = new LinkedList<>();
        if (root == null) {
            return root;
        }
        que.add(root);
        while (que.size() > 0) {
            int size = que.size();
            Node node = que.poll();
            if (node.left != null) {que.add(node.left);}
            if (node.right != null) {que.add(node.right);}
            for (int i = 1; i < size; i++) {
                Node next = que.poll();//彈出該層剩餘元素
                if (next.left != null) que.add(next.left);
                if (next.right != null) que.add(next.right);

                node.next = next;
                node = next;
            }

        }
        return root;
    }
}

117. 填充每個節點的下一個右側節點指針 II

給定一個二叉樹
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指針,讓這個指針指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指針設置為 NULL。
初始狀態下,所有 next 指針都被設置為 NULL。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

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

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        Queue<Node> que = new LinkedList<>();
        if (root == null) {
            return root;
        }
        que.add(root);
        while (que.size() > 0) {
            int size = que.size();
            Node node = que.poll();
            if (node.left != null) {que.add(node.left);}
            if (node.right != null) {que.add(node.right);}
            for (int i = 1; i < size; i++) {
                Node next = que.poll();//彈出該層剩餘元素
                if (next.left != null) que.add(next.left);
                if (next.right != null) que.add(next.right);

                node.next = next;
                node = next;
            }

        }
        return root;
    }
}
  • 離大譜,這題程式碼跟上題一樣,一模一樣

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) {
        Queue<TreeNode> que = new LinkedList<>();//新建一個隊列
        if (root == null) {
            return 0;
        }
        que.add(root);//把根節點放入隊列
        int count = 0;
        while (!que.isEmpty()) {
            //當隊列不為空時
            count++;
            ArrayList<Integer> item = new ArrayList<>();//內層鏈表
            int size = que.size();//隊列的大小
            while (size > 0) {
                TreeNode node = que.poll();//彈出當前結點
                if (node.left != null) {
                    que.add(node.left);
                }//把當前結點的左孩子加進去(如果有的話)
                if (node.right != null) {
                    que.add(node.right);
                }//把當前結點的右孩子加進去(如果有的話)
                size--;
            }
        }
        return count;
    }
}

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) {
        Queue<TreeNode> que = new LinkedList<>();//新建一個隊列
        if (root == null) {
            return 0;
        }
        que.add(root);//把根節點放入隊列
        int count = 0;
        while (!que.isEmpty()) {
            //當隊列不為空時
            count++;
            ArrayList<Integer> item = new ArrayList<>();//內層鏈表
            int size = que.size();//隊列的大小
            while (size > 0) {
                TreeNode node = que.poll();//彈出當前結點
                if (node.left != null) {
                    que.add(node.left);
                }//把當前結點的左孩子加進去(如果有的話)
                if (node.right != null) {
                    que.add(node.right);
                }//把當前結點的右孩子加進去(如果有的話)
                if(node.left==null&&node.right==null){
                    return count;
                }
                size--;
            }

        }
        return count;
    }
}

總結

  • 通過今天的題目大致掌握二叉樹的結構。深度優先遍歷方面掌握前序、中序、後續的遞歸實現和迭代實現。掌握廣度優先遍歷的模板(寫了十道層序遍歷的題目,就算是小豬也會了😐

  • 今天的題目自己寫出來的不多,除了最後幾道改模板的題,不知道是因為天太冷還是頭上戴的蝴蝶結封印了我的智慧的🙃

Tags: