Li Kou's notes have been opened to the public:
Portal
[Author: ArtBoy literature and art
Self-Improvement
There's no better way to overpower a trickle of doubt than with a flood of naked truth.
A flood of facts is the best way to break a trace of doubt.
Title Source:
https://leetcode-cn.com/leetbook/detail/illustration-of-algorithm/
Supporting learning documents:
https://www.kancloud.cn/alex_wsc/dataalg/1853982
Book recommendation:
Comic algorithm
Video recommendation:
https://www.bilibili.com/video/BV1E4411H73v
catalogue
1, Sword finger Offer 12. Path in matrix
Question:
Given an m x n two-dimensional character grid board and a string word word. If word exists in the grid, return true; Otherwise, false is returned.
Words must be formed alphabetically by letters in adjacent cells, where "adjacent" cells are those horizontally or vertically adjacent. Letters in the same cell cannot be reused.
For example, in 3 below × The matrix of 4 contains the word "ABCCED" (the letters in the word are marked).
Example 1:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" Output: true
Example 2:
Input: board = [["a","b"],["c","d"]], word = "abcd" Output: false
Tips:
1 <= board.length <= 200 1 <= board[i].length <= 200 board and word It consists of upper and lower case letters only
Solution:
Problem solving idea: DFS + pruning
AC Code:
class Solution { public boolean exist(char[][] board, String word) { char[] words = word.toCharArray(); for(int i = 0; i < board.length; i++){ for(int j = 0; j < board[0].length; j++){ if(dfs(board, words, i, j, 0)) return true; } } return false; } boolean dfs(char[][] board, char[] words, int i, int j, int k){ if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != words[k]) return false; // Subscript out of bounds if(k == words.length - 1) return true; // Match all board[i][j] = '\0'; // Invalid marker (the next step is to explore the way up, down, left and right. You can't walk through the past, '\ 0' to prevent repetition with the characters in words) boolean res = dfs(board, words, i+1, j, k+1) || dfs(board, words, i-1, j, k+1) || dfs(board, words, i, j+1, k+1) || dfs(board, words, i, j-1, k+1); // Up, down, right, left, parallel board[i][j] = words[k]; return res; } }
M. N is the size of matrix rows and columns, and K is the length of string word.
- Time complexity O(3K MN): in the worst case, it is necessary to traverse all schemes with a length of K string in the matrix, and the time complexity is O(3K); There are Mn starting points in the matrix, and the time complexity is O(MN).
- Calculation of the number of schemes: set the length of the string as K, and each character in the search can be selected in the up, down, left and right directions. Discard the back (last character) direction, and there are three options left. Therefore, the complexity of the number of schemes is O(3K).
- Space complexity O(K): the recursion depth in the search process does not exceed K, so the stack space accumulated by the system due to function calls occupies O(K) (because the stack space of system calls will be released after the function returns). In the worst case, K = MN and the recursion depth is Mn. At this time, the system stack uses the additional space of O(MN).
2, 13. Motion range of the robot
Question:
There is a grid of m rows and N columns on the ground, from coordinates [0,0] to coordinates [m-1,n-1]. A robot starts to move from the grid of coordinates [0,0]. It can move left, right, up and down one grid at a time (it cannot move outside the grid), nor can it enter the grid where the sum of digits of row coordinates and column coordinates is greater than k. For example, when k is 18, the robot can enter the grid [35, 37], because 3 + 5 + 3 + 7 = 18. But it cannot enter the grid [35, 38], because 3 + 5 + 3 + 8 = 19. How many grids can the robot reach?
Example 1:
Input: m = 2, n = 3, k = 1 Output: 3
Example 2:
Input: m = 3, n = 1, k = 0 Output: 1
Tips:
1 <= n,m <= 100 0 <= k <= 20
Solution:
Problem solving idea: DFS + pruning
Digital sum calculation template:
int sums(int x) int s = 0; while(x != 0) { s += x % 10; // Get the one digit number of x x = x / 10; // Move the decimal number of x one digit to the right, that is, delete one digit. } return s;
In this problem, the robot can only move one grid at a time, and only the digits and increments from X to x+1 are required for each calculation
(x + 1) % 10 != 0 ? s_x + 1 : s_x - 8;
explain:
- x = 11, x + 1 = 12, digit sum: 2, 3 (2 + 1)
- x = 19, x + 1 = 20, digit sum: 10, 2 (10-8)
According to the structure and connectivity of reachable solutions, it is easy to deduce that the robot can access all reachable solutions only by moving to the right and down.
AC Code:
class Solution { int m, n, k; boolean[][] visited; public int movingCount(int m, int n, int k) { this.m = m; this.n = n; this.k = k; this.visited = new boolean[m][n]; return dfs(0, 0, 0, 0); } public int dfs(int i, int j, int si, int sj){ // Coordinates, digits and if(i >= m || j >= n || si + sj > k || visited[i][j]) return 0; // prune visited[i][j] = true; // sign int down = dfs(i+1, j, cal(i, si), sj); // Next look int right = dfs(i, j+1, si, cal(j, sj)); // Right search return 1 + down + right; } public int cal(int x, int sum){ // Digit and increment return (x + 1) % 10 != 0 ? sum + 1 : sum - 8; } }
Problem solving idea: BFS
AC Code:
class Solution { public int movingCount(int m, int n, int k) { boolean[][] visited = new boolean[m][n]; int res = 0; LinkedList<int[]> queue = new LinkedList<>(); queue.add(new int[]{0, 0, 0, 0}); // i,j,si,sj while(!queue.isEmpty()){ int[] x = queue.removeFirst(); int i = x[0], j = x[1], si = x[2], sj = x[3]; if(i >= m || j >= n || si + sj > k || visited[i][j]) continue; visited[i][j] = true; res++; queue.add(new int[]{i+1, j , cal(i,si), sj}); queue.add(new int[]{i, j+1, si, cal(j,sj)}); } return res; } public int cal(int x, int sum){ return (x + 1)%10 != 0 ? sum + 1 : sum - 8; } }
3, Sword finger Offer 26. Substructure of tree
Question:
Input two binary trees a and B to judge whether B is the substructure of A. (the contract empty tree is not a substructure of any tree)
B is the substructure of A, that is, the same structure and node values as B appear in A.
For example:
Given tree A:
3 / \ 4 5 / \ 1 2
Given tree B:
4 / 1
Returns true because A subtree of B and A has the same structure and node values.
Example 1:
Input: A = [1,2,3], B = [3,1] Output: false
Example 2:
Input: A = [3,4,5,1,2], B = [4,1] Output: true
Limitations:
0 <= Number of nodes <= 10000
Solution:
Problem solving idea: first traverse A + judge whether A contains B (double-layer dfs)
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isSubStructure(TreeNode A, TreeNode B) { // An empty tree is not a substructure of any tree if(A == null || B == null) return false; // Current node judgment if(recur(A,B)) return true; // Left and right node judgment return isSubStructure(A.left, B) || isSubStructure(A.right, B); } // Compare current node boolean recur(TreeNode A, TreeNode B){ // B match end if(B == null) return true; // First judge whether it is null, and then judge whether its val is equal, otherwise a null pointer exception will be reported if(A == null || A.val != B.val) return false; return recur(A.left, B.left) && recur(A.right, B.right); } }
- Time complexity O(MN): where m and N are the number of nodes of tree A and tree B respectively; First traverse the tree a to occupy O(M), and each time call recur(A, B) to judge the occupation of O(N).
- Spatial complexity O(M): when both tree A and tree B degenerate into linked lists, the recursive call depth is the largest. When M ≤ n, the total recursive depth of traversing tree A and recursive judgment is M; When M > N, the worst case is to traverse to the leaf node of tree a, and the total recursion depth is M.
4, Sword finger Offer 27. Image of binary tree
Question:
Please complete a function, input a binary tree, and the function outputs its image.
For example, enter:
4 / \ 2 7 / \ / \ 1 3 6 9
Mirror output:
4 / \ 7 2 / \ / \ 9 6 3 1
Example 1:
Input: root = [4,2,7,1,3,6,9] Output:[4,7,2,9,6,3,1]
Limitations:
0 <= Number of nodes <= 1000
Solution:
Problem solving idea: recursion
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode mirrorTree(TreeNode root) { // It must be judged as null before taking value to prevent null exception if(root == null) return null; TreeNode temp = root.left; // Right flip left root.left = mirrorTree(root.right); // temp flip right root.right = mirrorTree(temp); return root; } }
- Time complexity O(N): where N is the number of nodes of the binary tree. To establish a binary tree image, you need to traverse all nodes of the tree, taking O(N) time.
- Space complexity O(N): in the worst case (when the binary tree degenerates into a linked list), the system needs to use stack space of O(N) size for recursion.
Solution idea: auxiliary stack traversal exchange
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode mirrorTree(TreeNode root) { if(root == null) return null; // Traverse the whole tree through the stack (store the nodes to be accessed and pop up the accessed nodes) LinkedList<TreeNode> stack = new LinkedList<>(){{add(root);}}; while(!stack.isEmpty()){ // Pop up the node being accessed TreeNode node = stack.removeLast(); // Record the left and right nodes for the next visit if(node.left != null) stack.add(node.left); if(node.right != null) stack.add(node.right); // exchange TreeNode temp = node.left; node.left = node.right; node.right = temp; } return root; } }
- Time complexity O(N): where N is the number of nodes of the binary tree. To establish a binary tree image, you need to traverse all nodes of the tree, taking O(N) time.
- Space complexity O(N): as shown in the figure below, in the worst case, stack stack can be stored at most at the same time
N
+
1
2
\frac{N+1}{2}
2N+1} nodes, occupying O(N) additional space.
5, Sword finger Offer 28. Symmetric binary tree
Question:
Please implement a function to judge whether a binary tree is symmetrical. If a binary tree is the same as its mirror, it is symmetrical.
For example, a binary tree [1,2,2,3,4,4,3] is symmetric.
1 / \ 2 2 / \ / \ 3 4 4 3
However, the following [1,2,2,null,3,null,3] is not mirror symmetric:
1 / \ 2 2 \ \ 3 3
Example 1:
Input: root = [1,2,2,3,4,4,3] Output: true
Example 2:
Input: root = [1,2,2,null,3,null,3] Output: false
Limitations:
0 <= Number of nodes <= 1000
Solution:
Solution idea: recursive traversal and comparison one by one
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isSymmetric(TreeNode root) { if(root == null) return true; return recur(root.left, root.right); } boolean recur(TreeNode L, TreeNode R){ // 50. R ends recursively at the same time if(L == null && R == null) return true; // L or R has an early end, with different values if(L == null || R == null || L.val != R.val) return false; return recur(L.left, R.right) && recur(L.right, R.left); } }
- Time complexity O(N): where N is the number of nodes in the binary tree. Each execution of recur() can judge whether a pair of nodes are symmetrical. Therefore, the recur() method can be called N/2 times at most.
- Spatial complexity O(N): as shown in the figure below, in the worst case (binary tree degenerates into linked list), the system uses a space of O(N).
6, Sword finger Offer 32 - I. print binary tree from top to bottom
Question:
Each node of the binary tree is printed from top to bottom, and the nodes of the same layer are printed from left to right.
For example:
Given binary tree: [3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7
return:
[3,9,20,15,7]
Tips:
Total number of nodes <= 1000
Solution:
Problem solving idea: BFS
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int[] levelOrder(TreeNode root) { if(root == null) return new int[0]; List<Integer> res = new ArrayList<>(); // BFS template LinkedList<TreeNode> queue = new LinkedList<>(); queue.add(root); while(!queue.isEmpty()){ TreeNode node = queue.removeFirst(); res.add(node.val); if(node.left != null) queue.add(node.left); if(node.right != null) queue.add(node.right); } // List to array int[] ans = new int[res.size()]; for(int i = 0; i < res.size(); i++){ ans[i] = res.get(i); } return ans; } }
- Time complexity O(N): N is the number of nodes in the binary tree, that is, BFS needs to cycle N times.
- Spatial complexity O(N): in the worst case, that is, when the tree is a balanced binary tree, there are at most N/2 tree nodes in the queue at the same time, and the additional space of O(N) size is used.
7, Sword finger Offer 32 - II. Print binary tree II from top to bottom
Question:
The binary tree is printed by layers from top to bottom, the nodes of the same layer are printed from left to right, and each layer is printed to one line.
For example:
Given binary tree: [3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7
Return its hierarchy traversal result:
[ [3], [9,20], [15,7] ]
Tips:
Total number of nodes <= 1000
Solution:
Problem solving idea: BFS
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root == null) return res; LinkedList<TreeNode> queue = new LinkedList<>(); queue.add(root); while(!queue.isEmpty()){ List<Integer> temp = new ArrayList<>(); // Sequence traversal and output int num = queue.size(); // Get the number of nodes in this layer while((num --) > 0){ TreeNode node = queue.removeFirst(); temp.add(node.val); if(node.left != null) queue.add(node.left); if(node.right != null) queue.add(node.right); } res.add(temp); } return res; } }
8, Sword finger Offer 32 - III. print binary tree III from top to bottom
Question:
Please implement a function to print the binary tree in zigzag order, that is, the first line is printed from left to right, the second layer is printed from right to left, the third line is printed from left to right, and so on.
For example:
Given binary tree: [3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7
Return its hierarchy traversal result:
[ [3], [20,9], [15,7] ]
Tips:
Total number of nodes <= 1000
Solution:
Solution: sequence traversal + double ended queue
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root == null) return res; LinkedList<TreeNode> queue = new LinkedList<>(); queue.add(root); while(!queue.isEmpty()){ LinkedList<Integer> temp = new LinkedList<>(); int num = queue.size(); // level traversal while((num --) > 0){ TreeNode node = queue.removeFirst(); if(res.size() % 2 == 0){ // The initial length is 0 temp.add(node.val); }else{ temp.addFirst(node.val); } if(node.left != null) queue.add(node.left); if(node.right != null) queue.add(node.right); } res.add(temp); } return res; } }
Problem solving ideas:
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root == null) return res; LinkedList<TreeNode> queue = new LinkedList<>(); queue.add(root); while(!queue.isEmpty()){ List<Integer> temp = new ArrayList<>(); int num = queue.size(); // level traversal while((num --) > 0){ TreeNode node = queue.removeFirst(); temp.add(node.val); if(node.left != null) queue.add(node.left); if(node.right != null) queue.add(node.right); } if(res.size()%2 != 0) Collections.reverse(temp); res.add(temp); } return res; } }
9, Sword finger Offer 34. A path with a certain value in a binary tree
Question:
Enter a binary tree and an integer, and print out all paths where the sum of node values in the binary tree is the input integer. A path is formed from the root node of the tree down to the leaf node.
A leaf node is a node that has no children.
Example:
Given the following binary tree, and target and target = 22,
5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1
return:
[ [5,4,11,2], [5,8,4,5] ]
Tips:
Total number of nodes <= 10000
Solution:
Solution idea: first order traversal + path record
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { LinkedList<List<Integer>> res = new LinkedList<>(); LinkedList<Integer> path = new LinkedList<>(); public List<List<Integer>> pathSum(TreeNode root, int target) { dfs(root, target); return res; } void dfs(TreeNode root, int tar){ if(root == null) return; path.add(root.val); tar -= root.val; if(tar == 0 && root.left == null && root.right == null){ res.add(new LinkedList(path)); } dfs(root.left, tar); dfs(root.right, tar); path.removeLast(); } }
10, Sword finger Offer 36. Binary search tree and bidirectional linked list
Question:
Enter a binary search tree and convert the binary search tree into a sorted circular two-way linked list. It is required that no new node can be created, and only the node pointer in the tree can be adjusted.
To better understand the problem, take the following binary search tree as an example:
We hope to transform this binary search tree into a two-way circular linked list. Each node in the linked list has a precursor and successor pointer. For a two-way circular linked list, the precursor of the first node is the last node, and the successor of the last node is the first node.
The following figure shows the linked list transformed from the above binary search tree. "head" refers to the node with the smallest element in the linked list.
In particular, we want the conversion to be done in place. After the conversion is completed, the left pointer of the node in the tree needs to point to the precursor and the right pointer of the node in the tree needs to point to the successor. You also need to return the pointer of the first node in the linked list.
Solution:
Solution idea: middle order traversal + two-way linked list + circular linked list
It is worth noting that the middle order traversal of the binary search tree in this problem can realize the increasing sequence
AC Code:
/* // Definition for a Node. class Node { public int val; public Node left; public Node right; public Node() {} public Node(int _val) { val = _val; } public Node(int _val,Node _left,Node _right) { val = _val; left = _left; right = _right; } }; */ class Solution { Node pre,head; public Node treeToDoublyList(Node root) { if(root == null) return null; dfs(root); // Head to tail docking head.left = pre; pre.right = head; return head; } void dfs(Node cur){ if(cur == null) return; // Medium order traversal dfs(cur.left); // Left // root // Double linked list template if(pre != null) pre.right = cur; else head = cur; cur.left = pre; // Pointer pre shift right pre = cur; dfs(cur.right); // right } }
- Time complexity O(N): N is the number of nodes of the binary tree, and all nodes need to be accessed for medium order traversal.
- Space complexity O(N): in the worst case, that is, when the tree degenerates into a linked list, the recursion depth reaches N, and the system uses O(N) stack space.
11, Sword finger Offer 37. Serialized binary tree
Question:
Please implement two functions to serialize and deserialize the binary tree respectively.
You need to design an algorithm to realize the serialization and deserialization of binary tree. There is no restriction on the execution logic of your sequence / deserialization algorithm. You only need to ensure that a binary tree can be serialized into a string and deserialize the string into the original tree structure.
Note: the input / output format is the same as that currently used by LeetCode. For details, please refer to the format of LeetCode serialized binary tree. You don't have to take this approach, you can also take other methods to solve the problem.
Example:
Input: root = [1,2,3,null,null,4,5] Output:[1,2,3,null,null,4,5]
Solution:
Solution: sequence traversal
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Codec { // Encodes a tree to a single string. public String serialize(TreeNode root) { if(root == null) return "[]"; StringBuilder res = new StringBuilder("["); // BFS LinkedList<TreeNode> queue = new LinkedList<>(){{add(root);}}; while(!queue.isEmpty()){ TreeNode node = queue.removeFirst(); if(node != null){ res.append(node.val + ","); queue.add(node.left); queue.add(node.right); }else res.append("null,"); } res.deleteCharAt(res.length() - 1); // Remove the last comma res.append("]"); return res.toString(); } // Decodes your encoded data to tree. public TreeNode deserialize(String data) { if(data.equals("[]")) return null; // string manipulation String[] vals = data.substring(1, data.length() - 1).split(","); // BFS int index = 0; // Traversal array pointer TreeNode root = new TreeNode(Integer.parseInt(vals[index++])); LinkedList<TreeNode> queue = new LinkedList<>(){{add(root);}}; while(!queue.isEmpty()){ TreeNode node = queue.removeFirst(); if(!vals[index].equals("null")){ node.left = new TreeNode(Integer.parseInt(vals[index])); queue.add(node.left); } index ++; if(!vals[index].equals("null")){ node.right = new TreeNode(Integer.parseInt(vals[index])); queue.add(node.right); } index ++; } return root; } } // Your Codec object will be instantiated and called as such: // Codec codec = new Codec(); // codec.deserialize(codec.serialize(root));
- Time complexity O(N): N is the number of nodes of the binary tree. Sequence traversal needs to access all nodes. In the worst case, it needs to access N + 1 null s. The overall complexity is
O( N + 1 2 \frac{N+1}{2} 2N+1) = O(N). - Spatial complexity O(N): in the worst case, the queue stores 2N+1 nodes (or N+1 null s) at the same time, using O(N); The list res uses O(N).
12, Sword finger Offer 38. Arrangement of strings
Question:
Enter a string and print out all the arrangements of characters in the string.
You can return this string array in any order, but there can be no duplicate elements.
Example:
Input: s = "abc" Output:["abc","acb","bac","bca","cab","cba"]
Limitations:
1 <= s Length of <= 8
Solution:
Problem solving ideas: dfs + backtracking
Illustration:
List all full permutations of 1, 2 and 3, and add dfs traversal to res one by one
For a string of length n (assuming that the characters do not repeat each other), the number of arrangement schemes is: n × (n−1) × (n−2)… × two × one
swap() function:
AC Code:
class Solution { List<String> res = new LinkedList<>(); char[] c; public String[] permutation(String s) { c = s.toCharArray(); dfs(0); return res.toArray(new String[res.size()]); } void dfs(int x) { if(x == c.length - 1) { res.add(String.valueOf(c)); // Add arrangement scheme return; } HashSet<Character> set = new HashSet<>(); for(int i = x; i < c.length; i++) { if(set.contains(c[i])) continue; // Repeat, so prune set.add(c[i]); swap(i, x); // Swap, fix c[i] in bit x dfs(x + 1); // Turn on fixed x + 1 st character swap(i, x); // Recovery exchange } } void swap(int a, int b) { char tmp = c[a]; c[a] = c[b]; c[b] = tmp; } }
- Time complexity O(N!N): n is the length of string s; The time complexity is linear with the number of schemes of string arrangement, and the number of schemes is n × (N−1) × (N−2)… × two × 1, that is, the complexity is O(N!); The string splicing operation join() uses O(N); Therefore, the overall time complexity is O(N!N).
- Space complexity O(N2): the recursion depth of full permutation is n, and the cumulative stack space used by the system is O(N); The maximum cumulative number of characters stored by the auxiliary Set in recursion is N + (N-1) +... + 2 + 1 = (N+1)N/2, that is, it occupies additional space of O(N2).
13, Sword finger Offer 54. The k-th node of the binary search tree
Question:
Given a binary search tree, please find the k-largest node.
Example 1:
input: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 output: 4
Example 2:
input: root = [5,3,6,2,4,null,null,1], k = 3 5 / \ 3 6 / \ 2 4 / 1 output: 4
Limitations:
1 ≤ k ≤ Number of binary search tree elements
Solution:
Solution idea: middle order traversal reverse order
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { int res, k; // Returned result, k public int kthLargest(TreeNode root, int k) { this.k = k; dfs(root); // Inverse middle order traversal return res; } void dfs(TreeNode root){ if(root == null) return; dfs(root.right); // right k--; if(k == 0){ res = root.val; return; } dfs(root.left); // Left } }
- Time complexity O(N): when the tree degenerates into a linked list (all right child nodes), the recursion depth is N regardless of the value of k, occupying O(N) time.
- Space complexity O(N): when the tree degenerates into a linked list (all right child nodes), the system uses a stack space of O(N).
14, Sword finger Offer 55 - I. depth of binary tree
Question:
Enter the root node of a binary tree to find the depth of the tree. The nodes (including root and leaf nodes) passing from root node to leaf node form a path of the tree, and the length of the longest path is the depth of the tree.
For example:
Given binary tree [3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7
Returns its maximum depth 3.
Tips:
Total number of nodes <= 10000
Solution:
Problem solving idea: DFS (post order traversal)
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root == null) return 0; // Export return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1; } }
- Time complexity O(N): N is the number of nodes in the tree. To calculate the depth of the tree, you need to traverse all nodes.
- Spatial complexity O(N): in the worst case (when the tree degenerates into a linked list), the recursion depth can reach N.
Problem solving idea: BFS
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root == null) return 0; LinkedList<TreeNode> queue = new LinkedList<>(){{add(root);}}; int res = 0; while(!queue.isEmpty()){ LinkedList<TreeNode> temp = new LinkedList<>(); // level traversal for(TreeNode node : queue){ if(node.left != null) temp.add(node.left); if(node.right != null) temp.add(node.right); } queue = temp; res ++; } return res; } }
- Time complexity O(N): N is the number of nodes in the tree. To calculate the depth of the tree, you need to traverse all nodes.
- Spatial complexity O(N): in the worst case (when the tree is balanced), the queue stores N/2 nodes at the same time.
15, Sword finger Offer 55 - II. Balanced binary tree
Question:
Enter the root node of a binary tree to judge whether the tree is a balanced binary tree. If the depth difference between the left and right subtrees of any node in a binary tree is no more than 1, it is a balanced binary tree.
Example 1:
Given binary tree [3,9,20,null,null,15,7]
3 / \ 9 20 / \ 15 7
Returns true.
Example 2:
Given binary tree [1,2,2,3,3,null,null,4,4]
1 / \ 2 2 / \ 3 3 / \ 4 4
Returns false.
Limitations:
0 <= Number of nodes in the tree <= 10000
Solution:
Problem solving idea: first order traversal + judgment depth (from top to bottom)
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isBalanced(TreeNode root) { if(root == null) return true; return Math.abs(dfs(root.left) - dfs(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right); } // Returns the depth of the node int dfs(TreeNode root){ if(root == null) return 0; return Math.max(dfs(root.left), dfs(root.right)) + 1; } }
16, Sword finger Offer 64. Find 1 + 2 +... + n
Question:
For 1 + 2 +... + n, it is required that keywords such as multiplication and division, for, while, if, else, switch, case and conditional judgment statements (A?B:C) cannot be used.
Example 1:
input: n = 3 output: 6
Example 2:
input: n = 9 output: 45
Limitations:
1 <= n <= 10000
Solution:
Solution idea: bit operation
AC Code:
class Solution { int res = 0; public int sumNums(int n) { boolean x = n > 1 && sumNums(n-1) > 0; res += n; return res; } }
17, Sword finger Offer 68 - I. nearest common ancestor of binary search tree
Question:
Given a binary search tree, find the nearest common ancestor of two specified nodes in the tree.
Baidu Encyclopedia defines the nearest public ancestor as: "for two nodes p and q with root tree T, the nearest public ancestor is expressed as a node x, which satisfies that x is the ancestor of p and q, and the depth of X is as large as possible (a node can also be its own ancestor)."
For example, give the following binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]
Example 1:
input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 output: 6 explain: The nearest common ancestor of node 2 and node 8 is 6.
Example 2:
input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 output: 2 explain: The nearest common ancestor of node 2 and node 4 is 2, Because according to the definition, the nearest common ancestor node can be the node itself.
explain:
The values of all nodes are unique. p,q Are different nodes and all exist in a given binary search tree.
Solution:
Problem solving idea: recursion
Binary lookup tree: unique value, left less than right
Definition of ancestor: if node p is in the left (right) subtree of node root, or p = root, root is said to be the ancestor of p.
Nearest common ancestor: set node root as a common ancestor of nodes P and Q. if its left child node root.left and right child node root.right are not the common ancestors of P and Q, root is called "nearest common ancestor".
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // On the right side of the root node if(root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right,p,q); // To the left of the root node if(root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left,p,q); // Different side return root; } }
- Time complexity O(N): where N is the number of binary tree nodes; One layer is excluded in each cycle. The minimum number of layers of binary search tree is logN (full binary tree) and the maximum is N (degenerated into linked list).
- Spatial complexity O(N): in the worst case, that is, when the tree degenerates into a linked list, the recursion depth reaches the number of layers N of the tree.
18, Sword finger Offer 68 - II. Nearest common ancestor of binary tree
Question:
Given a binary tree, find the nearest common ancestor of two specified nodes in the tree.
Baidu Encyclopedia defines the nearest public ancestor as: "for two nodes p and q with root tree T, the nearest public ancestor is expressed as a node x, which satisfies that x is the ancestor of p and q, and the depth of X is as large as possible (a node can also be its own ancestor)."
For example, give the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]
Example 1:
input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 output: 3 explain: The nearest common ancestor of node 5 and node 1 is node 3.
Example 2:
input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 output: 5 explain: The nearest common ancestor of node 5 and node 4 is node 5. Because according to the definition, the nearest common ancestor node can be the node itself.
explain:
The values of all nodes are unique. p,q Are different nodes and all exist in a given binary tree.
Solution:
Problem solving ideas:
AC Code:
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null || root == p || root == q) return root; // Export TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if(left != null && right != null) return root; // There are both left and right subtrees else return left != null ? left : right; } }