[Data structure]_8. Binary tree OJ

Table of contents

1. Topic 1: Check if two trees are the same

 2. Topic 2: Determine whether a tree is a subtree of another tree

3. Topic 3: Flip a binary tree

4. Topic 4: Determine whether a tree is a balanced binary tree

5. Topic 5: Determine whether a tree is a symmetric binary tree

6. Topic 6: Level order traversal of binary tree

7. Topic 7: Binary tree traversal

8. Topic 8: The nearest common ancestor of a binary tree

9. Topic 9: Construct a binary tree based on preorder and inorder traversal

10. Topic 10: Construct a binary tree based on inorder and postorder traversal

11. Topic 11: Create a string from a binary tree

12. Topic 12: Non-recursive implementation of binary tree preorder traversal

13. Topic 13: Non-recursive implementation of binary tree inorder traversal

14. Topic 14: Non-recursive implementation of binary tree post-order traversal


1. Topic 1: Check if two trees are the same

Topic link: 100. The same tree - LeetCode

Problem-solving ideas: recursive ideas: determine whether the root nodes are the same, whether the left subtrees are the same, and whether the right subtrees are the same;

The same judgment has two aspects: structure and value;

code:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        // 两树均为空
        if(p == null && q == null){
            return true;
        }
        // 两树一空一非空
        if((p == null && q != null)||(p != null && q == null)){
            return false;
        }
        // 两树均不为空
        // 两树根节点数据域值不同
        if(p.val != q.val){
            return false;
        }
        // 两树根节点数据域值相同
        return isSameTree(p.left,q.left) && isSameTree(p.right, q.right);
    }
}

Time complexity: O(min(m,n)); where mn is the number of nodes in the two trees;

 2. Topic 2: Determine whether a tree is a subtree of another tree

Topic link: 572. Subtree of another tree - LeetCode

Problem-solving idea: judge whether two trees are the same, recursively judge whether one is the left subtree of the other, and whether it is the right subtree;

code:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q){
        if(p == null && q == null){
            return true;
        }
        if((p == null && q != null) || (p != null && q == null)){
            return false;
        }
        if(p.val != q.val){
            return false;
        }
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null || subRoot == null){
            return false;
        }
        if(isSameTree(root, subRoot)){
            return true;
        }
        if(isSubtree(root.left,subRoot)){
            return true;
        }
        if(isSubtree(root.right, subRoot)){
            return true;
        }
        return false;
    }
}

Time complexity: O(s * t);

3. Topic 3: Flip a binary tree

Topic Link: 226. Flip Binary Tree - LeetCode

Problem-solving idea: When the binary tree is not empty, exchange the left and right subtrees of the binary tree, and then recursively exchange the left and right subtrees of the left subtree and the left and right subtrees of the right subtree;

code:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null){
            return null;
        }
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

4. Topic 4: Determine whether a tree is a balanced binary tree

Topic Link: 110. Balanced Binary Tree - LeetCode

Problem-solving ideas:

Code 1:

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }
        int leftH = maxDepth(root.left);
        int rightH = maxDepth(root.right);
        return  Math.abs(leftH - rightH) <2
        && isBalanced(root.left) 
        && isBalanced(root.right);
    }
    public int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = maxDepth(root.left);
        int rightHeight = maxDepth(root.right);
        return (leftHeight>rightHeight)?(leftHeight+1):(rightHeight+1);
    }
}

Time complexity: O(N²);

Code 2:

class Solution {
    public boolean isBalanced(TreeNode root) {
        return maxDepth(root) >=0;
    }
    public int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = maxDepth(root.left);
        if(leftHeight < 0){
            return -1;
        }
        int rightHeight = maxDepth(root.right);
        if(rightHeight < 0){
            return -1;
        }
        if(Math.abs(leftHeight - rightHeight) <= 1){
            return Math.max(leftHeight,rightHeight)+1;
        }else{
            return -1;
        }
    }
}

Time complexity: O(N);

5. Topic 5: Determine whether a tree is a symmetric binary tree

Topic Link: 101. Symmetric Binary Tree - LeetCode

code:

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        // 判断左子树的左树 和 右子树的右树是否对称
        return isSymmetricChild(root.left,root.right);
    }
    public boolean isSymmetricChild(TreeNode leftTree, TreeNode rightTree){
        if(leftTree == null && rightTree == null){
            return true;
        }
        if((leftTree == null && rightTree != null)||
        (leftTree != null && rightTree == null)){
            return false;
        }
        // 左右子树均不为空
        // 左右子树根节点数据不同
        if(leftTree.val != rightTree.val){
            return false;
        }
        // 左右子树根节点数据相同
        return isSymmetricChild(leftTree.left,rightTree.right) && 
        isSymmetricChild(leftTree.right, rightTree.left);

    }
}

6. Topic 6: Level order traversal of binary tree

Topic link: 102. Level order traversal of binary tree - LeetCode

code:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null){
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            List<Integer> tmp = new ArrayList<>();
            while(size != 0){
                TreeNode cur = queue.poll();
                tmp.add(cur.val);
                size--;
                if(cur.left != null){
                    queue.offer(cur.left);
                }
                if(cur.right != null){
                    queue.offer(cur.right);
                }
            }
            list.add(tmp);
        }
        return list;
    }
}

7. Topic 7: Binary tree traversal

Topic Link: Binary Tree Traversal_Niuke Topic_Niuke.com

code:

import java.util.Scanner;
class TreeNode{
    public char val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(char val){
        this.val = val;
    }
}
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            i=0;  // 将i置为0,防止多组测试i累加
            String str = in.nextLine();
            TreeNode root = createTree(str);
            inOrder(root);
        }
    }
    public static int i = 0;
    public static TreeNode createTree(String str){
        TreeNode root = null;
        if(str.charAt(i)!='#'){
            // 遍历字符串,不为空的字符创建结点:
            root = new TreeNode(str.charAt(i));
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
        }else{
            // 字符串遍历至#:
            i++;
        }
        return root;
    }
    public static void inOrder(TreeNode root){
        if(root == null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }
}

8. Topic 8: The nearest common ancestor of a binary tree

Topic link: 236. The nearest common ancestor of the binary tree - LeetCode

Problem-solving ideas:

Method 1: In addition to the case where one of the empty tree and pq is the root node, there are three cases: the first: pq is on the left and right sides of the root; the second: both pq are on the left of the root or Right; the third type: there is a node in pq that is the common ancestor;

code:

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return null;
        }
        if(p == root || q == root){
            return root;
        }
        // 分别在根结点的左右子树查找目标结点
        TreeNode leftRet = lowestCommonAncestor(root.left, p, q);
        TreeNode rightRet = lowestCommonAncestor(root.right, p, q);
        // 第一种情况:左右子树均有目标结点则根结点为公共祖先
        if(leftRet != null && rightRet != null){
            return root;
        }else if(leftRet != null){
            // 第二种情况: 右子树没有查询到目标结点:两个目标结点均在左子树
            return leftRet;
            // leftRet已经记录了左子树查询到的第一个目标结点
            // 同时由于2个目标结点均在左子树,即已经记录到的leftRet即是两个结点的最近公共祖先
        }else if(rightRet != null){
            // 左子树没有查询到目标结点:两个目标结点均在右子树
            return rightRet;
            // 同第一个else-if语句,rightRet即是2个目标结点的最近公共祖先
        }
        return null;
    }

Method 2: Build two stacks, respectively store each node of the pq two nodes starting from the root node, pop the stack from the stack with more nodes, start from the same number of elements in the two stacks, and pop the two stacks at the same time Compare whether the top elements of the stack are the same, the same is the common ancestor, and if they are not the same, compare the next element in turn;

code:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 建2个栈分别用于存放根结点root到目标结点p与q的路径结点
        Deque<TreeNode> stack1 = new LinkedList<>();
        getPath(root, p, stack1);
        Deque<TreeNode> stack2 = new LinkedList<>();
        getPath(root, q, stack2);
        // 判断栈大小,先出栈元素多的栈直至与另一个栈元素个数相同,两栈开始同时出栈元素
        int size1 = stack1.size();
        int size2 = stack2.size();
        if(size1> size2){
            int size = size1 - size2;
            while(size != 0){
                stack1.pop();
                size--;
            }
        }else{
            int size = size2 - size1;
            while(size != 0){
                stack2.pop();
                size--;
            }
        }
        // 此时两栈元素个数已经相同
        // 当两个栈均不为空时,逐个元素对比
        while(!stack1.isEmpty() && !stack2.isEmpty()){
            // 两栈栈顶元素不同则同时出栈
            if(stack1.peek() != stack2.peek()){
                stack1.pop();
                stack2.pop();
            }else{
                // 两栈栈顶元素相同:该结点为公共祖先
                return stack1.peek();
            }
        }
        return null;
    }
    public boolean getPath(TreeNode root, TreeNode node, Deque<TreeNode> stack){
        // 查找从根结点root到目标结点node路径上的结点并存放到栈stack中
        if(root == null || node == null){
            return false;
        }
        // 将当前结点入栈
        stack.push(root);
        // 判断该结点是否为目标结点
        if(root == node){
            return true;
        }
        // 判断该结点左子树中是否有目标结点
        boolean ret1 = getPath(root.left, node, stack);
        if(ret1 == true){
            return true;
        }
        // 判断该结点右子树中是否有目标结点
        boolean ret2 = getPath(root.right, node, stack);
        if(ret2 == true){
            return true;
        }
        // 左右子树均查询无果,则出栈该结点并返回空
        stack.pop();
        return false;
    }
}

Note: If the address of its parent node is stored in each node of the binary tree, changing the question is equivalent to finding the intersection node of two linked lists;

9. Topic 9: Construct a binary tree based on preorder and inorder traversal

Topic link: 105. Construct a binary tree from preorder and inorder traversal sequences - LeetCode

code:

class Solution {
    public int i=0;  //用于前序preorder遍历
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder, inorder, 0,inorder.length-1);
    }
    public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inBgein, int inEnd){
        if(inBgein > inEnd){   // 没有子树
            return null;
        }
        TreeNode root = new TreeNode(preorder[i]);  // root结点
        // 在中序遍历inorder中定位根结点root位置
        int rootIndex = findIndex(inorder, inBgein, inEnd, preorder[i]);
        i++;
        // 在中序遍历中确定根结点位置后,其左为左树,右为右树
        root.left = buildTreeChild(preorder, inorder, inBgein, rootIndex-1);
        root.right = buildTreeChild(preorder, inorder, rootIndex+1, inEnd);
        return root;
    }
    private int findIndex(int[] inorder, int inBgein, int inEnd, int key){
        for(int i=inBgein; i<= inEnd;i++){
            if(inorder[i] == key){
                return i;
            }
        }
        return -1;
    }
}

10. Topic 10: Construct a binary tree based on inorder and postorder traversal

Topic Link: 106. Construct Binary Tree from Inorder and Postorder Traversal Sequences - LeetCode

code:

class Solution {
    public int i =0;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        i = inorder.length-1;
        return  buildTreeChild(postorder, inorder, 0, inorder.length-1);
    }
    public TreeNode buildTreeChild(int[] postorder, int[] inorder, int inBegin, int inEnd){
        if(inBegin > inEnd){
            return null;
        }
        TreeNode root = new TreeNode(postorder[i]);
        int rootIndex = findIndex(inorder, inBegin, inEnd, postorder[i]);
        i--;
        root.right = buildTreeChild(postorder, inorder, rootIndex+1, inEnd);
        root.left = buildTreeChild(postorder, inorder, inBegin, rootIndex-1);
        return root;
    }
    private int findIndex(int[] inorder, int inBegin, int inEnd, int key){
        for(int j=inBegin;j<=inEnd;j++){
            if(inorder[j] == key){
                return j;
            }
        }
        return -1;
    }
}

11. Topic 11: Create a string from a binary tree

Topic link: 606. Create a string based on a binary tree - LeetCode

Problem-solving ideas: divided into the following three situations: (1) the left and right sides of the node are empty: return directly; (2) the left side of the node is not empty and the right side is empty: no need to add parentheses for the empty node; (3) the node If the left is empty and the right is not empty, add parentheses to the empty node;

code:

class Solution {
    public String tree2str(TreeNode root) {
        if(root == null){
            return null;
        }
        StringBuilder stringBuilder = new StringBuilder();
        tree2strChild(root, stringBuilder);
        return stringBuilder.toString();
    }
    public void tree2strChild(TreeNode node, StringBuilder stringBuilder){
        if(node == null){
            return;
        }
        stringBuilder.append(node.val);
        // 判断结点左子树
        if(node.left != null){
            // 结点左孩子不为空
            stringBuilder.append("(");
            tree2strChild(node.left, stringBuilder);
            stringBuilder.append(")");
        }else{
            // 结点左孩子为空
            // 情况1:结点右孩子不为空
            if(node.right != null){
                stringBuilder.append("()");
            }else{
                // 情况2:结点右孩子为空
                return;
            }
        }
        // 判断结点右子树
        if(node.right == null){
            // 结点右孩子为空:直接返回
            return;
        }else{
            // 结点右孩子不为空:递归结点的右子树
            stringBuilder.append("(");
            tree2strChild(node.right, stringBuilder);
            stringBuilder.append(")");
        }
    }
}

12. Topic 12: Non-recursive implementation of binary tree preorder traversal

Topic link: 144. Preorder traversal of binary tree - LeetCode

code:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        TreeNode cur = root;   // 用于遍历二叉树
        Deque<TreeNode> stack = new ArrayDeque<>();
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                ret.add(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            cur = top.right;
        }
        return ret;
    }
}

13. Topic 13: Non-recursive implementation of binary tree inorder traversal

Topic link: 94. Inorder traversal of binary tree - LeetCode

code:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        TreeNode cur = root;
        Deque<TreeNode> stack = new ArrayDeque<>();
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            ret.add(top.val);
            cur = top.right;
        }
        return ret;
    }
}

14. Topic 14: Non-recursive implementation of binary tree post-order traversal

Topic link: 145. Post-order traversal of binary tree - LeetCode

code:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        TreeNode cur = root;
        TreeNode prev = null;
        Deque<TreeNode> stack = new ArrayDeque<>();
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            // 后序遍历顺序为:根->左->右
            TreeNode top = stack.peek();  // 不可以直接pop栈顶元素
            // 当栈顶元素结点没有右子树时才可以打印根结点
            if(top.right == null || top.right == prev){
                ret.add(top.val);
                stack.pop();
                prev = top;
            }else{
                // 栈顶元素结点有右子树,优先遍历右子树后再打印根结点
                cur = top.right;
            }
        }
        return ret;
    }
}

Guess you like

Origin blog.csdn.net/m0_63299495/article/details/132133158