美文网首页
📔二叉树Book

📔二叉树Book

作者: 卡路fly | 来源:发表于2022-03-12 12:45 被阅读0次

    [toc]

    二叉树Book


    🌟 树的遍历

    // 递归写法
    List<Integer> list = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root != null) {
            list.add(root.val);
            preorderTraversal(root.left);
            preorderTraversal(root.right);
        }
        return list;
    }
    

    模板

    public List<Integer> preorderTraversal(TreeNode root) {
    
        List<Integer> list = new ArrayList<>();
        if(root == null) 
            return list;
        
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while(node!= null || !stack.isEmpty()) {
            while(node != null ){
                stack.push(node);
                node = node.left;
            }
    
            ......
    
        }
    
    
        return list;
    }
    

    1. 前序遍历

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null)
            return list;
    
        Stack<TreeNode> stack = new Stack<>();
        while(root != null || !stack.isEmpty()) {
            while(root != null) {
                stack.push(root);
                list.add(root.val);
                root = root.left;
            }
            if(!stack.isEmpty()){
                root = stack.pop();
                root = root.right;
            }
        }
        return list;
    }
    

    2. 中续遍历

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) 
            return list;
        
        Stack<TreeNode> stack = new Stack<>();
        while(root!= null || !stack.isEmpty()) {
            while(root != null ){
                stack.push(root);
                root = root.left;
            }
            if(!stack.isEmpty()){
                root = stack.pop();
                list.add(root.val);
                root = root.right;
            }
        }
    
        return list;
    }
    

    3. 后续遍历

    注意 node.right == null || node.right == visited

    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null)
            return list;
        
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root, visited = root;
        while(node!=null || !stack.isEmpty()) {
            while(node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.peek();
            if(node.right == null || node.right == visited) {
                stack.pop();
                list.add(node.val);
                visited = node;
                node = null;
            } else {
                node = node.right;
            }
            
        }
        return list;
    }
    

    4. 层续遍历

    思路:利用队列实现

    public List<List<Integer>> levelOrder(TreeNode root) {
            List<List<Integer>> res = new ArrayList<>();
            if(root == null)
                return res;
    
            Queue<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            while(!queue.isEmpty()) {
                int size = queue.size();
                List<Integer> list = new ArrayList<>();
                for(int i = 0 ; i < size; i++) {
                    TreeNode node = queue.poll();
                    list.add(node.val);
                    
                    if(node.left != null)
                        queue.offer(node.left);
                    if(node.right != null)
                        queue.offer(node.right);
                }
                res.add(list);
            }
        
            return res;
        }
    

    🌟 递归解决问题

    二叉树最大深度

    // 自底向上
    public int maxDepth(TreeNode root) {
        if(root == null)
            return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
    }
    
    

    自顶向下方法

    int res = 0;
    // 自顶向下
    public int maxDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        max(root, 1);
        return res;
    }
    
    private void max(TreeNode node, int answer) {
        if(node == null)
            return;
    
        if(node.left == null && node.right == null){
            res = Math.max(res, answer);
        }
    
        max(node.left, answer + 1); 
        max(node.right, answer + 1); 
    }
    

    对称二叉树

    注意 node1 == null && node2 == null 判断

    class Solution {
        public boolean isSymmetric(TreeNode root) {
            return isSymmetric(root,root);
        }
    
        boolean isSymmetric(TreeNode node1, TreeNode node2) {
            if(node1 == null && node2 == null)
                return true;
            if(node1 == null)
                return false;
            if(node2 == null)
                return true;
    
            if(node1.val != node2.val) {
                return false;
            }
    
            return isSymmetric(node1.left, node2.right) && isSymmetric(node1.right, node2.left);
        }
    }
    

    🌟 路径总和

    注意
    a) curSum传递
    b) if(node == null) return false;

    public boolean hasPathSum(TreeNode root, int targetSum) {
            if(root == null)
                return false;
    
            return getSum(root,targetSum);
        }
    
    
        boolean getSum(TreeNode node, int targetSum) {
            if(node == null) 
                return false;
            
            targetSum -= node.val;
    
            if(targetSum == 0 && node.left == null && node.right == null) {
                return true;
            }
            return getSum(node.left, targetSum) || getSum(node.right, targetSum);
        }
    

    🌟 从中序与后序遍历序列构造二叉树

    注意,return null && 边界不要算node

    class Solution {
        public TreeNode buildTree(int[] inorder, int[] postorder) {
            return buildTree(inorder,0, inorder.length-1, postorder,0 , postorder.length-1);
        }
    
    
         public TreeNode buildTree(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, 
    int postEnd) {
            if(inStart > inEnd || postStart > postEnd)
                return null;
            // 根节点
            TreeNode node = new TreeNode(postorder[postEnd]);
            for(int i = inStart;i<= inEnd;i++){
                // 找到中序的根节点,分隔左右子树
                if(inorder[i] == postorder[postEnd]){
                    // 取左子树递归构造
                    node.left = buildTree(inorder, inStart, i - 1, postorder, postStart, postStart + i - inStart-1);
                    node.right = buildTree(inorder, i + 1 , inEnd, postorder, postStart + i - inStart, postEnd-1);
                }
            }
            return node;
        }
    }
    

    从前序与中序遍历序列构造二叉树

    public TreeNode buildTree(int[] preorder, int[] inorder) {
            return buildTree(preorder, 0, preorder.length - 1, inorder , 0, inorder.length - 1);
        }
    
        public TreeNode buildTree(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
            if(preStart > preEnd || inStart > inEnd)
                return null;
    
            TreeNode node = new TreeNode(preorder[preStart]);
    
            for(int i = inStart;i <= inEnd; i++) {
                if(inorder[i]==preorder[preStart]) {
                    node.left = buildTree(preorder, preStart+ 1, preStart + i - inStart, inorder,inStart,i-1);
                    node.right = buildTree(preorder, preStart + 1 + i - inStart, preEnd, inorder,i+1,inEnd);
                }
            }
            return node;
        }
    

    🌟 填充每个节点的下一个右侧节点指针

    思路: 基于层续遍历

    class Solution {
        public Node connect(Node root) {
            if(root == null)
                return root;
    
            Queue<Node> queue = new LinkedList<>();
            queue.offer(root);
    
            while(!queue.isEmpty()) {
                int size = queue.size();
                Node lastNode = null;
                for(int i = 0; i < size; i++) {
                    Node node = queue.poll();
                    if(lastNode != null) {
                        lastNode.next = node;
                    }
                    lastNode = node;
                    if(node.left != null)
                        queue.offer(node.left);
                    if(node.right != null)
                        queue.offer(node.right);
                }
            }
            return root;
        }
    }
    

    填充每个节点的下一个右侧节点指针 II

    class Solution {
        public Node connect(Node root) {
            if(root == null)
                return root;
    
            // 每次初始指向上一排的第一个链表
            Node cur = root;
        
            while(cur != null){
                // 第一个空节点
                Node pre = new Node(0);
                // 使用 node 串联
                Node node = pre;
                while(cur != null) {
                    if(cur.left != null){
                        node.next = cur.left;
                        node = node.next;
                    }
                    if(cur.right != null){
                        node.next = cur.right;
                        node = node.next;
                    }
                    cur = cur.next;
                }
                // 指回该行第一个
                cur = pre.next;
            }
            
            return root;    
        }
    }
    

    🌟 二叉树的最近公共祖先

    思路:
    a) 递归把所有节点放入map
    b) 把p节点的祖先们放入visited
    c)找q结点祖先和p重合

    class Solution {
        private HashMap<Integer,TreeNode> map = new HashMap<>();
        private List<Integer> visited =  new ArrayList<>();
        
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            getParents(root);
            // 找p节点的祖先们,放入visited
            TreeNode cur = p;
            while (cur != null) {
                visited.add(cur.val);
                // cur再找亲爸爸
                cur = map.get(cur.val);
            }
            cur = q;
            while (cur != null) {
                // 如果发现当前节点和p祖先们【visited】有重合
                if(visited.contains(cur.val)) {
                    return cur;
                } 
                // cur再找亲爸爸
                cur = map.get(cur.val);
            }
            return null;
        }
        
        public void getParents(TreeNode root) {
            if(root.left==null && root.right==null)
                return;
                
            if(root.left!=null){
                map.put(root.left.val,root);
                getParents(root.left);
            }
            if(root.right!=null){
                map.put(root.right.val,root);
                getParents(root.right);
            }
        }
    }
    

    🌟 二叉树的序列化与反序列化

    Tips: 递归

    序列化:
    root=null 为 #, 使用递归添加到StringBuilder中

    反序列化:队列 + 递归

    • 将string进行分隔后加入队列
    • 使用递归进行还原
    public class Codec {
    
        // Encodes a tree to a single string.
        public String serialize(TreeNode root) {
            if(root == null)
                return "#,";
    
            StringBuilder res = new StringBuilder(root.val + ",");
            res.append(serialize(root.left));
            res.append(serialize(root.right));
            return res.toString(); 
        }
    
        // Decodes your encoded data to tree.
        public TreeNode deserialize(String data) {
            if(data == null || data == "#,")
                return null;
            
            String[] ss = data.split(",");
            Queue<String> queue = new LinkedList<>();
            for(String s: ss)
                queue.offer(s);
    
            return pre(queue);
        }
    
    
        TreeNode pre(Queue<String> queue) {
            String val = queue.poll();
            if (val.equals("#"))
                return null;
    
            TreeNode node = new TreeNode(Integer.parseInt(val));
            node.left = pre(queue);
            node.right = pre(queue);
            return node;
        }
    }
    

    相关文章

      网友评论

          本文标题:📔二叉树Book

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