Leetcode notes -- modification and construction of binary tree in binary tree chapter

Posted by crimaniak on Thu, 17 Feb 2022 05:15:27 +0100

Catalogue of series articles

I Array type problem solving method 1: dichotomy
II Array type problem solving method 2: Double finger needle method
III Array type problem solving method 3: sliding window
IV Array type problem solving method 4: simulation
V The basic operation and classic topics of the linked list
Vi Classic title of hash table
VII Classic title of string
VIII KMP of string
IX Solution: double pointer
X Classic title of stack and queue
Xi top-K problem in stack and queue
XII The first, middle and last order traversal of binary tree
XIII Sequence traversal of binary tree and related topics
XIV Binary tree part of binary tree attributes related topics
Updating

preface

Modification of binary tree: such as flipping, merging, etc.
Construction of binary tree: such as constructing binary tree according to pre order traversal and middle order traversal or post order traversal and middle order traversal.
The question brushing route comes from: Code Capriccio

Inscription

226. Flip binary tree

Leetcode link
Turn over the two nodes of the tree and return to the two root s of the tree.

Example 1:
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]

Example 2:
Input: root = [2,1,3]
Output: [2,3,1]

Example 3:
Input: root = []
Output: []

Solution:
Traverse the binary tree and exchange the values of the left and right child nodes

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return null;
        invertTree(root.left);
        invertTree(root.right);
        // Pre order and subsequent traversal are OK. Here is post order traversal
        swap(root);
        return root;
    }
    // exchange
    public void swap(TreeNode root) {
        TreeNode node = root.left;
        root.left = root.right;
        root.right = node;
    }
}

106. Construct binary tree from middle order and post order traversal sequences

Leetcode link
Given two integer arrays inorder and postorder, inorder is the middle order traversal of the binary tree and postorder traversal of the same tree, please construct and return this binary tree.

Example 1:
Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output: [3,9,20,null,null,15,7]

Example 2:
Input: inorder = [-1], postorder = [-1]
Output: [- 1]

Solution:

  1. The last node of post order traversal is the root node.
  2. Traversing the array in middle order, the left side is all the nodes of the left subtree, and the right side is all the nodes of the right subtree. We know the number of nodes n of the left subtree
  3. In the post order traversal array, the first n nodes from the left are the nodes of the left subtree, and the following nodes are the nodes of the right subtree except the last one is the root node

Use recursive writing:

  1. In addition to the two traversal arrays, the parameter needs to pass in the interval of the left subtree node and the interval of the right subtree node in the two arrays. The interval is uniformly closed on the left and open on the right
  2. After recursion of the left and right subtrees, the root node is returned. As the child node of upper recursion
  3. The postorder traversal array postorder is used to determine the root node. The middle order traversal array inorder is divided by the root node to obtain the left and right subtree intervals and the number of left subtree nodes of inorder
  4. According to the number of left subtree nodes, the node intervals of the left and right subtrees of the postorder traversal array postorder are obtained
  5. The inorder of the middle order traversal array has no nodes (each method is divided) and returns null
  6. There is only one node left in inorder, which will be returned
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return build(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }
    public TreeNode build(int[] inorder, int inLeft, int inRight,
                            int[] postorder, int postLeft, int postRight) {
        // There are no nodes in the interval
        if (inRight - inLeft == 0) {
        	return null;        
        }               
        // There is only one node left, and the subscript is inLeft (because the interval is left closed and right open)
        if (inRight - inLeft == 1) {
            return new TreeNode(inorder[inLeft]);
        }
        
        // The last element is traversed in sequence, which is the root node of the current interval subtree
        int rootVal = postorder[postRight - 1];
        TreeNode root = new TreeNode(rootVal);
        // Split point subscript
        int rootIndex = -1;
        // Find the root node in the middle order traversal. The left is the left subtree node and the right is the right subtree node
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
        // Number of nodes in the left subtree: rootIndex - inLeft, then the following sequence traverses the sub array:
        //[postLeft, postLeft + number of left subtree nodes) is the node of the left subtree,
        //[postLeft + number of left subtree nodes, postright - 1 (the last node is the root node, minus 1)) is the right subtree interval
        root.left = build(inorder, inLeft, rootIndex, 
        		postorder, postLeft, postLeft + (rootIndex - inLeft));
        root.right = build(inorder, rootIndex + 1, inRight,
                postorder,postLeft + (rootIndex - inLeft) , postRight - 1);
        // Returns the root node of the current interval subtree
        return root;
    }
}

105. Construct binary tree from preorder and inorder traversal sequences

Leetcode link
Given two integer arrays preorder and inorder, where preorder is the preorder traversal of the binary tree and inorder is the inorder traversal of the same tree, please construct the binary tree and return its root node.

Example 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

Example 2:
Input: preorder = [-1], inorder = [-1]
Output: [- 1]
Solution:
The difference is that the root node is on the leftmost side of the preceding traversal array, so the recursive interval of the lower layer changes slightly

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return build(preorder, 0, preorder.length, inorder, 0, inorder.length);
    }
    public TreeNode build(int[] preorder, int preLeft, int preRight,
                            int[] inorder, int inLeft, int inRight) {
		// There are no nodes                            
        if (inRight - inLeft == 0) {
            return null;
        }
        // There is only one node left
        if (inRight - inLeft == 1) {
            return new TreeNode(inorder[inLeft]);
        }
        int rootVal = preorder[preLeft];
        // Root node of current interval subtree
        TreeNode root = new TreeNode(rootVal);
        // Split point
        int rootIndex = -1;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootVal) {
            	// The subscript of the root node is the partition point
                rootIndex = i;
                break;
            }
        }
        // Number of nodes in the left subtree: rootIndex - inLeft, then the following sequence traverses the sub array:
        //Node interval of left subtree: [preLeft+ 1 (the first is the root node, so + 1), preLeft+ 1 + number of nodes of left subtree)
        //Right subtree node interval: [preLeft+ 1 + number of left subtree nodes, preRight) 
        root.left = build(preorder, preLeft + 1, preLeft + 1 + (rootIndex - inLeft), 
                        inorder, inLeft, rootIndex);
        root.right = build(preorder, preLeft + 1 + (rootIndex - inLeft), preRight,
                        inorder, rootIndex + 1, inRight);
        return root;
    }
}

654. Maximum binary tree

Leetcode link
Give a non repeating integer array nums. The maximum binary tree can be constructed recursively from nums with the following algorithm:
Create a root node with the maximum value in nums.
Recursively construct the left subtree on the subarray prefix to the left of the maximum.
Recursively construct the right subtree on the subarray suffix to the right of the maximum.
Returns the largest binary tree constructed by nums.

Example 1:
Input: num = [3,2,1,6,0,5]
Output: [6,3,5,null,2,0,null,null,1]
Explanation: recursive calls are as follows:

  • The maximum value in [3,2,1,6,0,5] is 6, the left part is [3,2,1], and the right part is [0,5].
    • The left part is the maximum value of [1,3], and the right part is the maximum value of [1,3].
      • Empty array, no child nodes.
      • The maximum value in [2,1] is 2, the left part is [] and the right part is [1].
        • Empty array, no child nodes.
        • There is only one element, so the child node is a node with a value of 1.
    • The maximum value in [0,5] is 5, the left part is [0], and the right part is [].
      • There is only one element, so the child node is a node with a value of 0.
      • Empty array, no child nodes.

Example 2:
Input: num = [3,2,1]
Output: [3,null,2,null,1]
Solution:
If the above two questions are met, then this question is very simple.
Find the maximum number in the array as the split point. The left is the left subtree and the right is the right subtree

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return build(nums, 0, nums.length);
    }
    public TreeNode build(int[] nums, int left, int right) {
        if (right - left <= 0) {
            return null;
        }
        if (right - left == 1) {
            return new TreeNode(nums[left]);
        }
        int rootVal = Integer.MIN_VALUE;
        int maxIndex = -1;
        for (int i = left; i < right; i++) {
            if (nums[i] > rootVal) {
                rootVal = nums[i];
                maxIndex = i;         
            }
        }
        TreeNode root = new TreeNode(rootVal);
        root.left = build(nums, left, maxIndex);
        root.right = build(nums, maxIndex + 1, right);
        return root;
    }
}

617. Merge binary tree

Leetcode link
Here are two binary trees: root1 and root2.
Imagine that when you overlay one tree over the other, some nodes on the two trees will overlap (while others won't). You need to merge the two trees into a new binary tree. The merging rule is: if two nodes overlap, add the values of the two nodes as the new values of the merged nodes; Otherwise, the non null node will be directly used as the node of the new binary tree.
Returns the merged binary tree.
Note: the merge process must start at the root node of the two trees.

Example 1:
Input: root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
Output: [3,4,5,5,4,null,7]

Example 2:
Input: root1 = [1], root2 = [1,2]
Output: [2,2]
Solution:
The returned binary tree does not overlap with the merged tree nodes

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        return build(root1, root2);
    }
    public TreeNode build(TreeNode root1, TreeNode root2) {
        if (root1 == null && root2 == null) {
            return null;
        }
        TreeNode root = null;
        if (root1 == null) {
        	// The first node is empty
            root =  new TreeNode(root2.val);
            // Root1 is empty, root1 Left will cause null pointer exception, and the left child node will continue to be null during recursion
            root.left = build(root1, root2.left);
            root.right = build(root1, root2.right);         
        } else if (root2 == null) {
        	// The second node is empty
            root = new TreeNode(root1.val);
            root.left = build(root1.left, root2);
            root.right = build(root1.right, root2);
        } else {
        	// The two tree nodes are not null, and val is added
            root = new TreeNode(root1.val + root2.val);
            root.left = build(root1.left, root2.left);
            root.right = build(root1.right, root2.right);
        }
        return root;
    }
}

In order to simplify the code, if a tree is empty, you can directly return to the root node of the subtree of another tree and connect the subtree to the merged tree

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        return build(root1, root2);
    }
    public TreeNode build(TreeNode root1, TreeNode root2) {
        if (root1 == null) {
        	// Returns the root node of the subtree that is not empty
            return root2;
        }
        if (root2 == null) {
            return root1;
        }
        TreeNode root = new TreeNode(root1.val + root2.val);
        root.left = build(root1.left, root2.left);
        root.right = build(root1.right, root2.right);
        return root;
    }
}

Topics: Algorithm leetcode linked list