Force buckle around knot 04 - as deep as the sea

Posted by ectraz on Mon, 29 Nov 2021 04:57:26 +0100

It feels great to punch in!! Harvest is full, every day has a sense of mission to get up early!!

November is coming to an end, and my trip to Li Kou is only a one-day absence. I hope to continue my efforts next month and stick to it!!

Learn the recursive traversal of binary tree and hang these questions

Preorder traversal

recursion

public static void beforeSearch(Node node) {
    if (node != null) {
        System.out.print(node.value + " ");
        beforeSearch(node.leftNode);
        beforeSearch(node.rightNode);
    }
}

non-recursive

//    Non recursive preorder traversal
//    Left and right in traversal order
public static void before(Node node) {
    LinkedList<Node> list1 = new LinkedList<>();
    //        Storage ancestor node
    Node newNode = node;
    // The end condition is that all nodes are accessed
    while (newNode != null || !list1.isEmpty()) {
        //            If the child node is not empty, the node value is output, its left subtree is accessed, and the node is stacked to facilitate access to its right subtree
        if (newNode != null) {
            System.out.print(newNode.value + " ");
            list1.push(newNode);
            newNode = newNode.leftNode;
        } else { // If the child node is empty, access the right subtree of the parent node
            Node tempNode = list1.pop();
            newNode = tempNode.rightNode;
        }
    }
}

Medium order traversal

recursion

//    Middle order traversal recursion
public static void middleSearch(Node node) {
    if (node != null) {
        middleSearch(node.leftNode);
        System.out.print(node.value + " ");
        middleSearch(node.rightNode);
    }
}

non-recursive

//    Non recursive middle order traversal
//    Traversal order left middle right
public static void middle(Node node) {
    LinkedList<Node> list2 = new LinkedList<>();
    Node newNode = node;
    while (newNode != null || !list2.isEmpty()) {
        if (newNode != null) {
            list2.push(newNode);
            newNode = newNode.leftNode;
        } else {
            Node tempNode = list2.pop();
            System.out.print(tempNode.value + " ");
            newNode = tempNode.rightNode;
        }
    }
}

Subsequent traversal

recursion

//    Postorder traversal recursion
public static void afterSearch(Node node) {
    if (node != null) {
        afterSearch(node.leftNode);
        afterSearch(node.rightNode);
        System.out.print(node.value + " ");
    }
}

non-recursive

//    Non recursive postorder traversal
//    Traversal order left and right middle
//    You can speculate that the reverse of preorder traversal is postorder traversal
public static void after(Node node) {
    LinkedList<Node> list3 = new LinkedList<>();
    LinkedList<Node> list4 = new LinkedList<>();
    if (node != null) {
        list3.push(node);
    }
    while (!list3.isEmpty()) {
        Node newNode = list3.pop();
        list4.push(newNode);
        if (newNode.leftNode != null) {
            list3.push(newNode.leftNode);
        }
        if (newNode.rightNode != null) {
            list3.push(newNode.rightNode);
        }
    }

    while (!list4.isEmpty()) {
        System.out.print(list4.pop().value + " ");
    }
}

There is a set of fixed templates for the front, middle and back order. I prefer to write this because I have always written this before. As for the unified writing method of the front, middle and back, it is a little difficult for me to understand

After learning the recursive and non recursive traversal of binary tree, you can hang these three questions

144. Preorder traversal of binary tree

145. Post order traversal of binary tree

94. Middle order traversal of binary tree

Learn the level traversal of binary tree and hang these questions

level traversal

public static void level(Node node) {
    Queue<Node> queue = new LinkedList<>();
    queue.add(node);
    while (!queue.isEmpty()) {
        Node newNode = queue.poll();
        System.out.print(newNode.value + " ");
        if (newNode.leftNode != null) {
            queue.add(newNode.leftNode);
        }
        if (newNode.rightNode != null) {
            queue.add(newNode.rightNode);
        }
    }
}

102. Sequence traversal of binary tree

107. Sequence traversal of binary tree II

199. Right view of binary tree

429. Sequence traversal of n-ary tree

515. Find the maximum value in each tree row

116. Populate the next right node pointer for each node

117. Fill in the next right node pointer II of each node

104. Maximum depth of binary tree

111. Minimum depth of binary tree

226. Flip binary tree

Problem solving ideas

Let's talk about my idea first. I use hierarchical traversal, because the core of flipping binary tree is to exchange the left and right children of the parent node, so I talk about each layer by layer, and the left and right children of each layer have exchanged positions

Then tell me how to do it! From this problem to scalp numbness, the core of this problem has just talked about exchanging the two child nodes of the parent node, so we can use preorder traversal or postorder traversal to exchange, but we can't use middle order traversal. Why? Because the nodes on the same side will be traversed twice, you can know that the recursion of this problem is still very simple

Core code

level traversal

class Solution {
    public TreeNode invertTree(TreeNode root) {
        LinkedList<TreeNode> queue = new LinkedList<>();
        TreeNode node = root;
        if(node != null){
            queue.add(node);
        }
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i = 0; i < size; i++){
                TreeNode temp = queue.poll();
                if(temp.left != null){
                    queue.add(temp.left);
                }
                if(temp.right != null){
                    queue.add(temp.right);
                }
                swap(temp);
            }
        }
        return root;
    }

    public void swap(TreeNode node) {
        TreeNode temp = new TreeNode();
        temp = node.left;
        node.left = node.right;
        node.right = temp;
    }
}

Recursive traversal

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root != null) {
            curorder(root);
        }
        return root;
    }

    //Preorder traversal
    public void curorder(TreeNode root) {
        //The child who traversed the leaf node
        if(root == null) {
            return;
        }
        swap(root);
        curorder(root.left);
        curorder(root.right);
    }

    //Exchange node
    public void swap(TreeNode node) {
        TreeNode temp = new TreeNode();
        temp = node.left;
        node.left = node.right;
        node.right = temp;
    }
}

Time complexity

level traversal

O(n) each node needs to be traversed once

recursion

O(n) each node needs to be traversed once

Spatial complexity

level traversal

O(n) opens up additional queues for hierarchical traversal

recursion

The height of O(n) binary tree determines the depth of recursion. In the best case, it is O(logn), and in the worst case, the binary tree is chain O(n)

101. Symmetric binary tree

Problem solving ideas

The recursion of this problem is a little special. Suppose that there are k nodes in layer X of the binary tree, k1,k2,k2... kn-2,kn-1,kn. Compare the first k1,kn. In the case of the left child of k2,kn-1 and the right child of another node, we can't use the conventional front, middle and rear traversal. The conditions for the recursive end of the two nodes also have to be handled uniformly. If both are empty, it means that the nodes are the same. If one is empty and the other is not empty, it means that the nodes are different. If both are not empty but the values are different, it means that they are different, If the two are not empty but the values are the same, they are the same

Core code

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) return true;
        return compare(root.left, root.right);
    }

    public boolean compare(TreeNode l, TreeNode r) {
        //Exclude empty nodes first
        if(l == null && r == null){
            return true;
        }else if(l == null || r == null){
            return false;
        }else if(l.val != r.val){
            return false;
        }
        return compare(l.left, r.right) && compare(l.right, r.left);
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

104. Maximum depth of binary tree

Problem solving ideas

This problem is to find the distance from the root node to the farthest leaf node, and use preorder traversal to find the depth. In fact, we can also use sequence traversal and postorder traversal to find the height. For this problem, we use the preorder traversal of binary tree to find the height of left subtree and right subtree, and finally find the maximum value to get the result

Core code

class Solution {
    public int maxDepth(TreeNode root) {
        int depth = 0; // Initialize to 0
        if(root != null) { // Exclude the case where root is empty
            depth = searchDepth(root);
        }
        return depth;
    }
    //Preorder traversal depth
    public int searchDepth(TreeNode root) {
        //Returns 1 when traversing the leaf node
        if(root.left == null && root.right == null) {
            return 1;
        }
        int depth = 1;
        //Preorder traversal is abbreviated
        depth += Math.max(maxDepth(root.left), maxDepth(root.right));
        return depth;
    }
}

Time complexity

O(n) each node is traversed

Spatial complexity

O(n)

111. Minimum depth of binary tree

Problem solving ideas

It is basically the same as 104, but it is worth repeating here. It is worth noting that empty nodes do not form a tree!! In other words, if any number is empty, it will not participate in the comparison

222. Number of nodes of complete binary tree

Problem solving ideas

Use preorder traversal to access each node

Core code

class Solution {
    public int countNodes(TreeNode root) {
        //Determines whether the recursive end condition traverses to the leaf node
        if(root == null){
            return 0;
        }
        //Define the total number of recursions for each layer
        int sum = 1; // front
        sum += countNodes(root.left); // Left
        sum += countNodes(root.right); // right
        return sum;
    }
}

Time complexity

O(n)

Spatial complexity

O(logn)

110. Balanced binary tree

Problem solving ideas

The height is traversed by post order. The process of post order traversal is similar to backtracking

Core code

class Solution {    public boolean isBalanced(TreeNode root) {        return getDepth(root) == -1 ? false : true;    }    //Involving post order traversal of height (refer to the process of post order recursive traversal) public int getDepth(TreeNode node) {/ / the recursion termination condition traverses the leaf node if (node = = null) {return 0;} int leftdepth = GetDepth (node. Left); if (leftdepth = = - 1) return - 1; / / left int rightdepth = GetDepth (node. Right) ; if (rightdepth = = - 1) return - 1; / / right / / check whether the absolute value of the difference between the left and right subtrees of the node is greater than 1. If it is greater than 1, it means that the binary tree is not balanced. If the binary tree is balanced, return the maximum value of the left and right subtrees to return ABS (leftdepth - rightdepth) > 1? - 1: 1 + math.max (leftdepth, rightdepth); / / in} public int ABS (int val){        return val > 0 ? val : -val;    }}

Time complexity

O(n)

Spatial complexity

O(logn)

257. All paths of binary tree

Problem solving ideas

It involves the idea of backtracking. Add the current node. If this node is a leaf node, it means that a path has been accessed and added to the result set. Otherwise, check the left and right subtrees for recursion and backtracking

Core code

class Solution {    public List<String> binaryTreePaths(TreeNode root) {        List<String> result = new LinkedList<>();        List<Integer> temp = new LinkedList<>();        if(root != null){            backTracking(root, result, temp);            return result;        }        return result;    }        public void backTracking(TreeNode root,List<String> result,List<Integer> temp){        //The value added to the current node. The following code can ensure that the node is not empty temp.add(root.val)// Traverse to the leaf node if (root. Left = = null & & root. Right = = null) {StringBuffer sb = new stringbuffer(); for (int i = 0; I < temp. Size() - 1; I + +) {sb. Append (temp. Get (I) + "- >");} sb. Append (temp. Get (temp. Size() - 1)); result. Add (sb. Tostring());} //Ensure that the node is not empty in the next recursion if (root. Left! = null) {backtracking (root. Left, result, temp); / / backtrack temp.remove(temp.size() - 1);} / / ensure that the node is not empty in the next recursion if (root. Right! = null) {backtracking (root. Right, result, temp) / / backtracking temp.remove(temp.size() - 1);}}}

Time complexity

O(n)

Spatial complexity

O(n)

404. Sum of left leaves

Problem solving ideas

To judge whether a node is a left leaf, I use a flag to indicate it, so I don't have to record the parent node of the node

Core code

class Solution {
    int sum = 0;

    public int sumOfLeftLeaves(TreeNode root) {
        if (root != null) {
            searchLeftLeaves(root, false);
            return sum;
        }
        return sum;
    }

    public void searchLeftLeaves(TreeNode root, boolean flag) {
        //Traverse to leaf node
        if (root.left == null && root.right == null && flag) {
            sum += root.val;
            return;
        }
        if (root.left != null) {
            searchLeftLeaves(root.left, true);
        }
        if (root.right != null) {
            searchLeftLeaves(root.right, false);
        }
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

513. Find the value in the lower left corner of the tree

Problem solving ideas

I use sequence traversal in ontology, because I want to access the first node of each layer. This problem is a little different from the previous problem. The previous problem is to traverse the left leaf, and the value in the lower left corner may be the right leaf, so the idea is completely different

Core code

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        //Define results
        int result = 0;
        //level traversal 
        LinkedList<TreeNode> queue = new LinkedList<>();
        TreeNode node = root;
        if(node != null){
            queue.add(node);
        }
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i = 0; i < size; i++){
                TreeNode temp = queue.pop();
                //For sequence traversal, record the leftmost value of each layer
                if(i == 0){
                    result = temp.val;
                }
                if(temp.left != null){
                    queue.add(temp.left);
                }
                if(temp.right != null){
                    queue.add(temp.right);
                }
            }
        }
        return result;
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

112. Path sum

Problem solving ideas

Recursive backtracking, this problem has nothing to say

Core code

class Solution {
    int sum = 0;
    boolean result = false;

    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root != null){
            backTracking(root, targetSum);
        }
        return result;
    }

    //recursion tracing 
    public void backTracking(TreeNode root, int targetSum) {
        //Traverse to leaf node
        if(root.left == null && root.right == null){
            //Add the value of the leaf node
            sum += root.val;
            //If the sum value is the same as the target value, the result returns true
            if(sum == targetSum) {
                result = true;
            }
            //Subtracting the value of the leaf node is equivalent to a backtrace
            sum -= root.val;
        }

        if(root.left != null){
            //recursion
            sum += root.val;
            backTracking(root.left, targetSum);
            //to flash back
            sum -= root.val;
        }
        if(root.right != null){
            //recursion
            sum += root.val;
            backTracking(root.right, targetSum);
            //to flash back
            sum -= root.val;
        }
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

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

Problem solving ideas

There are three kinds of DFS for binary trees, i.e. pre order, mid order and post order. Only mid order, post order and pre order and mid order can be obtained by traversing a tree in pairs, because pre order and post order are special, Their root nodes are located at the front and back of a tree. According to the root node, its left and right subtrees can be found in the middle order traversal. Repeat this step until a tree is constructed

Core code

class Solution {
    // inorder traversal
    // postorder traversal
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return build(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }

    //Left closed right open
    public TreeNode build(int[] inorder, int inLeft, int inRight, 
                          int[] postorder, int postLeft, int postRight) {
        //There are no elements in the recursive end condition array
        if(inRight - inLeft < 1){
            return null;
        }
        //Last node remaining
        if(inRight - inRight == 1){
            return new TreeNode(inorder[inLeft]);
        }
        //The last node in the post order traversal is the root node
        TreeNode node = new TreeNode(postorder[postRight - 1]);
        //Find this node in the middle order traversal
        int index = 0;
        for(int i = inLeft; i < inRight; i++){
            if(inorder[i] == node.val){
                index = i;
                break;
            }
        }
        //In the middle order traversal, the left side of the root node is the left subtree, and the right side of the root node is the right subtree
        //Calculated according to index
        node.left = build(inorder, inLeft, index, postorder, postLeft, postLeft + (index - inLeft));
        node.right = build(inorder, index + 1, inRight, postorder,postLeft + (index - inLeft), postRight - 1);
        return node;
    }
}

105. Construct binary tree from preorder and inorder traversal sequences You can also easily win this question

654. Maximum binary tree

Problem solving ideas

After the above two questions are won, this question is equivalent to constructing a binary tree according to the maximum and middle order traversal

Core code

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        //Left close right open principle
        return buildTree(nums, 0, nums.length);
    }

    public TreeNode buildTree(int[] nums, int treeLeft, int treeRight) {
        if(treeRight - treeLeft < 1) {
            return null;
        }
        if(treeRight - treeLeft == 1) {
            return new TreeNode(nums[treeLeft]);
        }
        //Get the maximum value in the array as the root node
        int[] max = searchMax(nums, treeLeft, treeRight);
        TreeNode node = new TreeNode(max[0]);
        //Find the position of the maximum value in the array
        int index = max[1];
        node.left = buildTree(nums, treeLeft, index);
        node.right = buildTree(nums, index + 1, treeRight);
        return node;
    }

    //Find the maximum value of the array and its subscript function within the specified range
    public int[] searchMax(int[] nums, int treeLeft, int treeRight){
        int[] max = new int[2];
        for(int i = treeLeft; i < treeRight; i++) {
            if(max[0] < nums[i]) {
                max[0] = nums[i];
                max[1] = i;
            }
        }
        return max;
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

617. Merge binary tree

Problem solving ideas

There are four cases of merging binary trees. The first is that the nodes of two trees are empty, so there is no need to merge. The second and third are that the node of one tree is empty and returns the node of the other tree. The fourth is to integrate the nodes of two trees

Core code

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) {
            return root2;
        }       
        if(root2 == null) {
            return root1;
        }
        if(root1 != null && root2 != null) {
            root1.val += root2.val;
            root1.left = mergeTrees(root1.left,root2.left);
            root1.right = mergeTrees(root1.right,root2.right);
        }     
        return root1;     
    }
}

Time complexity

O(n)

Spatial complexity

O(n)

summary

It's not finished yet. The learning goal of this week is to deeply understand BST, AVL and red black tree, and brush the remaining binary tree topics. Come on!!!

Topics: Algorithm leetcode