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!!!