Tree
[toc]
TREE
Binary trees can be classified based on their structure and properties. Here are the main classifications of binary trees:
Based on Node Relationships
Full Binary Tree:
- Every node has either 0 or 2 children.
- Also known as a strictly binary tree.
Complete Binary Tree:
All levels are completely filled except possibly for the last level.
The last level has all nodes as left as possible.
Perfect Binary Tree:
- All internal nodes have two children, and all leaf nodes are at the same level.
Balanced Binary Tree:
- The height of the left and right subtrees of any node differ by at most one.
Degenerate (or Pathological) Tree:
- Each parent node has only one child. This degenerates the tree into a linked list.
Based on Specific Properties
- Binary Search Tree (BST):
- For each node, all elements in the left subtree are less than the node, and all elements in the right subtree are greater.
- AVL Tree:
- A self-balancing binary search tree where the difference in heights between the left and right subtrees cannot be more than one for all nodes.
- Red-Black Tree:
- A self-balancing binary search tree with an extra bit of storage per node (the color), which helps balance the tree during insertions and deletions.
- Splay Tree:
- A self-adjusting binary search tree with the additional property that recently accessed elements are quick to access again.
Special Types
- Threaded Binary Tree:
- A binary tree where pointers that would normally be null are used to point to the in-order predecessor or successor.
- Heaps:
- Max-Heap: A complete binary tree where the value of each node is greater than or equal to the values of its children.
- Min-Heap: A complete binary tree where the value of each node is less than or equal to the values of its children.
Application-Specific Trees
- Expression Tree:
- A tree used to represent expressions, where the leaves are operands and internal nodes are operators.
- Decision Tree:
- A tree used in decision analysis, where nodes represent decisions or outcomes.
Traversal-Based Classification
- Binary Tree Traversal Types
- In-Order Traversal: Left, Root, Right
- Pre-Order Traversal: Root, Left, Right
- Post-Order Traversal: Left, Right, Root
- Level-Order Traversal: Level by level from root to leaves
1 | public class TreeNode { |
in-order pre-order post-order traversal
Recursion
- Determine the parameters and return value of the recursive function: Since we need to collect the values of the nodes in pre-order traversal, we need to pass a list to store the node values. We don’t need to process any other data or return a value, so the return type of the recursive function is
void. The code is as follows:
1 | void preOrderTraversal(TreeNode cur, List<Integer> list) |
- Determine the termination condition: During recursion, we need to know when to end the recursion. This is when the current node being traversed is null. Therefore, if the current node is null, we simply return. The code is as follows:
1 |
|
- Determine the logic for a single layer of recursion: Pre-order traversal follows the order: root, left, right. In a single layer of recursion, we first process the root node’s value, then traverse the left subtree, and finally the right subtree. The code is as follows:
1 | list.add(cur.val); // Root |
144.Binary Tree Preorder Traversal
Easy
Given the root of a binary tree, return the preorder traversal of its nodes’ values.
1 | class Solution { |
94. Binary Tree Inorder Traversal
Easy
Given the root of a binary tree, return the inorder traversal of its nodes’ values.
1 | class Solution { |
145. Binary Tree Postorder Traversal
Easy
Given the root of a binary tree, return the postorder traversal of its nodes’ values.
1 | class Solution { |
iterative method
STACK
1 | // 前序遍历顺序:中-左-右,入栈顺序:中-右-左 |
level order traversal
226 and 101, using recursion is more efficient, but level order traversal can also solve the problem
226. Invert Binary Tree (recursion)
Easy
Given the root of a binary tree, invert the tree, and return its root.
Example 1:
1 | Input: root = [4,2,7,1,3,6,9] |
1 | // recursion |
101. Symmetric Tree (recursion)
😍Easy
Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).
Example 1:
1 | Input: root = [1,2,2,3,4,4,3] |
1 | class Solution { |
|| &&
1 | public class LogicalAndExample { |
when to use recursion in tree problems:
Traversal: Recursion is commonly used for tree traversal, such as in-order, pre-order, and post-order traversals. These traversal methods involve visiting each node of the tree in a specific order.
Transformation: Recursion can be used to transform or modify the tree in some way. This can include tasks like inverting a binary tree, as shown in the first example, or flattening a tree structure.
Validation and Comparison: Recursion is often used to validate the structure or properties of a tree, such as checking if a binary tree is symmetric, as shown in the second example. Recursive algorithms can compare subtrees and validate whether certain conditions hold true.
Searching and Path Finding: Recursive algorithms can be employed to search for nodes in a tree or find paths within the tree, such as finding the shortest path between two nodes or finding the common ancestor of two nodes.
Backtracking: In certain scenarios, backtracking is needed, especially in problems where you need to explore different paths or combinations within the tree. Recursion is well-suited for backtracking algorithms.
Divide and Conquer: Recursive divide-and-conquer algorithms are frequently used in tree problems where you break down the problem into smaller subproblems, solve each subproblem recursively, and then combine the results.
here are some examples of tree problems where recursion is commonly used:
- Binary Tree Traversals: Problems requiring in-order, pre-order, or post-order traversals of a binary tree. For example, printing the nodes of a binary tree in in-order traversal.
- Depth-First Search (DFS): DFS on a tree is inherently recursive. Problems involving exploring all possible paths from the root to leaves, or finding a specific node, often use recursion. For instance, checking if a path exists from the root to a given leaf node.
- Binary Tree Modification: Tasks like inverting a binary tree or converting a binary search tree into a sorted doubly linked list can be efficiently solved using recursion.
- Binary Search Trees (BSTs): Many operations on BSTs, such as insertion, deletion, and searching, can be implemented recursively.
- Symmetric Trees and Identical Trees: Problems checking if a tree is symmetric around its center or if two trees are identical often use recursive algorithms to compare corresponding nodes.
- Lowest Common Ancestor (LCA): Finding the lowest common ancestor of two nodes in a binary tree can be solved using recursion by traversing the tree and tracking the paths to the nodes.
- Maximum/Minimum Depth of Binary Tree: Calculating the maximum or minimum depth of a binary tree involves traversing the tree recursively and tracking the depth of each node.
- Validate Binary Search Tree (BST): Verifying whether a binary tree is a valid BST typically involves a recursive approach to check if each node satisfies the BST property.
Binary tree level order traversal
102. Binary Tree Level Order Traversal
Medium
Given the root of a binary tree, return the level order traversal of its nodes’ values. (i.e., from left to right, level by level).
Example 1:
1 | Input: root = [3,9,20,null,null,15,7] |
1 | class Solution { |
Recursion method
104. Maximum Depth of Binary Tree
😭😍Easy
Given the root of a binary tree, return its maximum depth.
A binary tree’s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Example 1:
1 | Input: root = [3,9,20,null,null,15,7] |
1 | // first try: (Recursion) |
- ```c++
// post order traversal
class Solution {
public:
int getdepth(TreeNode* node) {
if (node == NULL) return 0;
int leftdepth = getdepth(node->left); // 左
int rightdepth = getdepth(node->right); // 右
int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
}
int maxDepth(TreeNode* root) {
return getdepth(root);
}
};Input: root = [3,9,20,null,null,15,7]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
* [height vs. depth](https://www.geeksforgeeks.org/height-and-depth-of-a-node-in-a-binary-tree/)
**The depth of a node is the number of edges from the root to the node.**
**The height of a node is the number of edges from the node to the deepest leaf**
## [111. Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/)
[solution](https://programmercarl.com/0111.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE)
😭Easy
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
**Note:** A leaf is a node with no children.
**Example 1:**

Output: 21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
```java
class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) { //!!!!!!!!!
return rightDepth + 1;
}
if (root.right == null) { //!!!!!!!!!
return leftDepth + 1;
}
// 左右结点都不为null
return Math.min(leftDepth, rightDepth) + 1;
}
}
222. Count Complete Tree Nodes
😭 Easy
Given the root of a complete binary tree, return the number of the nodes in the tree.
According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
Design an algorithm that runs in less than O(n) time complexity.
Example 1:
1 | Input: root = [1,2,3,4,5,6] |
1 | class Solution { |
110. Balanced Binary Tree - tree height
😍Easy
Given a binary tree, determine if it is height-balanced.
A height-balanced binary tree is a binary tree in which the depth of the two subtrees of every node never differs by more than one.
Example 1:
1 | Input: root = [3,9,20,null,null,15,7] |
高度,后序遍历。(本题)
深度,前序遍历。you can’t solve this problem by compare the depth of the left and right tree.
1 | // my solution |
1 | // daimasuixianglu |
257. Binary Tree Paths - tree depth
😍Easy
Given the root of a binary tree, return all root-to-leaf paths in any order.
A leaf is a node with no children.
Example 1:
1 | Input: root = [1,2,3,null,5] |
1 | class Solution { |
1 | // carl |
404. Sum of Left Leaves
😭😭😭 Easy
Given the root of a binary tree, return the sum of all left leaves.
A leaf is a node with no children. A left leaf is a leaf that is the left child of another node.
Example 1:
1 | Input: root = [3,9,20,null,null,15,7] |
1 | // first try, wrong |
一定要通过父节点来判断其子节点是不是我们想要的元素
404 wrap up
In tree-related questions, particularly when dealing with recursion, it’s crucial to understand when to return a certain value. Here’s a summary:
- Base Case: Always define a base case for recursion. This is the stopping condition that prevents infinite recursion. Typically, it’s when you reach a leaf node or a null node in the tree.
- Determine Return Values:
- For functions calculating a result (like sum of node values, count of nodes, etc.), decide what value to return at each recursive step.
- If you need to accumulate a result (like in sum or count problems), return the partial result up the recursion stack.
- If you’re searching for a particular node or property, decide what value represents success or failure and return accordingly.
- Conditional Checks:
- In conditional checks within the recursive function, ensure you’re correctly identifying the condition you’re interested in.
- If a condition is met, you may need to perform certain actions before continuing the recursion.
- Passing Information:
- If you need to pass additional information or state between recursive calls, ensure it’s being handled correctly. This could be done via function parameters or by updating global or class-level variables (though the latter should be used sparingly).
- Returning Values vs. Continuing Recursion:
- Determine whether the current recursive call should return a value (e.g., if it’s contributing to a sum) or continue the recursion (if more exploration of the tree structure is needed).
Applying these principles to your code, the mistake lies in prematurely returning the sum when encountering a left leaf node. Instead, the sum should be accumulated and then returned after both left and right subtrees are explored.
Here’s the corrected code:
1 | class Solution { |
Returning the sum when you encounter a left leaf node prematurely terminates the recursion and may lead to incorrect results. Let’s break down why this is problematic:
- Incomplete Traversal: Returning immediately when a left leaf node is found means you’re not exploring the entire tree. The recursive function should traverse the entire tree to compute the sum of all left leaves correctly.
- Ignoring Right Subtree: By returning early, you’re completely ignoring the right subtree of the current node. This could lead to missing out on potential left leaves in the right subtree, which should also be considered in the final sum.
- Accumulation Issue: If you return the sum immediately when encountering a left leaf node, you’re not correctly accumulating the sum of all left leaves. Each left leaf node’s value should contribute to the final sum, and prematurely returning may lead to missing out on some of these values.
- Incorrect Result: Due to the incomplete traversal and premature return, the final result may be incorrect. It won’t reflect the true sum of all left leaves in the tree.
To ensure the correct computation of the sum of all left leaves, it’s essential to explore both left and right subtrees completely before returning any value. This ensures that all relevant nodes are considered and that the sum is accurately calculated.
513. Find Bottom Left Tree Value 6/10/2024
😭😭😭Medium
Given the root of a binary tree, return the leftmost value in the last row of the tree.
Example 1:
1 | Input: root = [2,1,3] |
Example 2:
1 | Input: root = [1,2,3,4,null,5,6,null,null,7] |
1 | class Solution { |
如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。 前中后序,都是优先遍历左节点。
To find the leftmost leaf node, we can employ preorder traversal (although inorder and postorder traversals would also suffice since this problem does not involve processing of intermediate nodes, prioritizing the left side suffices). Ensure left-first search and then record the deepest leaf node encountered. This will be the value of the leftmost leaf node in the last row of the tree.
112. Path Sum
Easy
Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.
A leaf is a node with no children
Example 1:
1 | Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 |
1 | class Solution { |
我的方法会遍历每一个node,
carl的方法是遍历到符合条件的方法就停止了
1 | // carl |
相信很多同学都会疑惑,递归函数什么时候要有返回值,什么时候没有返回值,特别是有的时候递归函数返回类型为bool类型。
那么接下来我通过详细讲解如下两道题,来回答这个问题:
再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
本篇通过leetcode上112. 路径总和 和 113. 路径总和ii 详细的讲解了 递归函数什么时候需要返回值,什么不需要返回值。
113. Path Sum II
Medium
Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where the sum of the node values in the path equals targetSum. Each path should be returned as a list of the node values, not node references.
A root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.
Example 1:
1 | Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 |
1 | class solution { |
106. Construct Binary Tree from Inorder and Postorder Traversal
Mediu
Given two integer arrays inorder and postorder where inorder is the inorder traversal of a binary tree and postorder is the postorder traversal of the same tree, construct and return the binary tree.
Example 1:
1 | Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] |
1 | class Solution { |
654. Maximum Binary Tree 6/11/2024
😭😭Medium
You are given an integer array nums with no duplicates. A maximum binary tree can be built recursively from nums using the following algorithm:
- Create a root node whose value is the maximum value in
nums. - Recursively build the left subtree on the subarray prefix to the left of the maximum value.
- Recursively build the right subtree on the subarray suffix to the right of the maximum value.
Return the maximum binary tree built from nums.
Example 1:
1 | Input: nums = [3,2,1,6,0,5] |
构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。
1 | // first try !!!wrong!!! |
617. Merge Two Binary Trees
Easy
You are given two binary trees root1 and root2.
Imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge the two trees into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of the new tree.
Return the merged tree.
Note: The merging process must start from the root nodes of both trees.
Example 1:
1 | Input: root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7] |
Example 2:
1 | Input: root1 = [1], root2 = [1,2] |
1 | class Solution { |
700. Search in a Binary Search Tree
Easy
You are given the root of a binary search tree (BST) and an integer val.
Find the node in the BST that the node’s value equals val and return the subtree rooted with that node. If such a node does not exist, return null.
Example 1:
1 | Input: root = [4,2,7,1,3], val = 2 |
1 |
|
很多录友写递归函数的时候 习惯直接写 searchBST(root->left, val),却忘了 递归函数还有返回值。
递归函数的返回值是什么? 是 左子树如果搜索到了val,要将该节点返回。 如果不用一个变量将其接住,那么返回值不就没了。
所以要 result = searchBST(root->left, val)。
– carl
98. Validate Binary Search Tree
😭😭😭Medium
Given the root of a binary tree, determine if it is a valid binary search tree (BST).
A valid BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node’s key.
- The right subtree of a node contains only nodes with keys greater than the node’s key.
- Both the left and right subtrees must also be binary search trees.
Example 1:
1 | Input: root = [2,1,3] |
1 | class Solution { |
有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。
中序遍历,一直更新maxVal,一旦发现maxVal >= root->val,就返回false,注意元素相同时候也要返回false。
The issue with returning
trueimmediately after settingmax = rootin your code is that it would prematurely end the recursive traversal of the binary tree, preventing the algorithm from checking the entire tree for BST validity.In a BST, it is crucial to ensure that for every node, all nodes in its left subtree are smaller, and all nodes in its right subtree are larger. This check must be applied to every node in the tree. By returning
trueimmediately after updatingmax, you would stop the recursion and fail to verify the nodes in the right subtree.
530. Minimum Absolute Difference in BST 6/12/2024
Easy
Given the root of a Binary Search Tree (BST), return the minimum absolute difference between the values of any two different nodes in the tree.
Example 1:
1 | Input: root = [4,2,6,1,3] |
1 | class Solution { |
题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。
注意是二叉搜索树,二叉搜索树可是有序的。
遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。
- 如何记录前一个节点的指针,其实实现起来是很简单的
遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点。
同时要学会在递归遍历的过程中如何记录前后两个指针,这也是一个小技巧,学会了还是很受用的。
501. Find Mode in Binary Search Tree
Easy
Given the root of a binary search tree (BST) with duplicates, return all the mode(s) (i.e., the most frequently occurred element) in it.
If the tree has more than one mode, return them in any order.
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than or equal to the node’s key.
- The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
- Both the left and right subtrees must also be binary search trees.
Example 1:
1 | Input: root = [1,null,2,2] |
- 如果不是二叉搜索树
如果不是二叉搜索树,最直观的方法一定是把这个树都遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合。
- 二叉搜索树
这里其实只需要遍历一次就可以找到所有的众数。
那么如何只遍历一遍呢?
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中。
万一,这个maxCount此时还不是真正最大频率呢。
所以下面要做如下操作:
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了。
1 |
|
1 | //explaination |
236. Lowest Common Ancestor of a Binary Tree
Medium
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Example 1:
1 | Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 |
1 | class Solution { |
- why post order traversal?
both left and right subtrees need to be fully traversed before processing the current node.
the current node requires both its left and right subtrees to determine the lowest common ancestor (LCA), so left and right subtree need to be traversed first.
*
为什么left为空,right不为空,目标节点通过right返回呢?
如图:
explanation for
if(left == null && right != null) return right;
if(left != null && right == null) return left;
if(left != null && right != null) return root;
图中节点10的左子树返回null,右子树返回目标值7,那么此时节点10的处理逻辑就是把右子树的返回值(最近公共祖先7)返回上去!
这里也很重要,可能刷过这道题目的同学,都不清楚结果究竟是如何从底层一层一层传到头结点的。
那么如果left和right都为空,则返回left或者right都是可以的,也就是返回空。
那么寻找最小公共祖先,完整流程图如下:
- 假如说p是q的父节点, 那其实算法走到p的时候就会直接返回,就不会再往下走了!!!
235. Lowest Common Ancestor of a Binary Search Tree 6/13/2024
😭 Medium
Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Example 1:
1 | Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 |
1 | class Solution { |
如图,我们从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点5,此时可以说明 q 和 p 一定分别存在于 节点 5的左子树,和右子树中。
此时节点5是不是最近公共祖先? 如果 从节点5继续向左遍历,那么将错过成为p的祖先, 如果从节点5继续向右遍历则错过成为q的祖先。
所以当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先。
理解这一点,本题就很好解了。
1 | // Carl solution |
- 确定单层递归的逻辑
在遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭又闭)
需要注意的是此时不知道p和q谁大,所以两个都要判断
代码如下:
1 | if (cur->val > p->val && cur->val > q->val) { |
细心的同学会发现,在这里调用递归函数的地方,把递归函数的返回值left,直接return。
1 | //236 |
1 | if (递归函数(root->left)) return ; |
My understanding: if theres returned value from root.left, then wont go into 递归函数(root->right)
1 | left = 递归函数(root->left); |
本题就是标准的搜索一条边的写法,遇到递归函数的返回值,如果不为空,立刻返回。
如果 cur->val 小于 p->val,同时 cur->val 小于 q->val,那么就应该向右遍历(目标区间在右子树)。
1 | if (cur->val < p->val && cur->val < q->val) { |
剩下的情况,就是cur节点在区间(p->val <= cur->val && cur->val <= q->val)或者 (q->val <= cur->val && cur->val <= p->val)中,那么cur就是最近公共祖先了,直接返回cur。
701. Insert into a Binary Search Tree
😭😭Medium
You are given the root node of a binary search tree (BST) and a value to insert into the tree. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST.
Notice that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them.
Example 1:
1 | Input: root = [4,2,7,1,3], val = 5 |
1 | class Solution { |
只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。
插入任何一个节点,都可以在叶子节点上操作
450. Delete Node in a BST
😭😭Medium
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
- Search for a node to remove.
- If the node is found, delete the node.
Example 1:
1 | Input: root = [5,3,6,2,4,null,7], key = 3 |
✨✨✨ think about how return statement work here✨✨✨
1 | class Solution { |
- 确定单层递归的逻辑
这里就把二叉搜索树中删除节点遇到的情况都搞清楚。
有以下五种情况:
第一种情况:没找到删除的节点,遍历到空节点直接返回了
找到删除的节点
第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
读完本篇,大家会发现二叉搜索树删除节点比增加节点复杂的多。
因为二叉搜索树添加节点只需要在叶子上添加就可以的,不涉及到结构的调整,而删除节点操作涉及到结构的调整。
这里我们依然使用递归函数的返回值来完成把节点从二叉树中移除的操作。
这里最关键的逻辑就是第五种情况(删除一个左右孩子都不为空的节点),这种情况一定要想清楚。
而且就算想清楚了,对应的代码也未必可以写出来,所以这道题目既考察思维逻辑,也考察代码能力。
669. Trim a Binary Search Tree
😭😭 Medium
Given the root of a binary search tree and the lowest and highest boundaries as low and high, trim the tree so that all its elements lies in [low, high]. Trimming the tree should not change the relative structure of the elements that will remain in the tree (i.e., any node’s descendant should remain a descendant). It can be proven that there is a unique answer.
Return the root of the trimmed binary search tree. Note that the root may change depending on the given bounds.
Example 1:
1 | Input: root = [1,0,2], low = 1, high = 2 |
1 | class Solution { |
108. Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/)
Easy
Given an integer array nums where the elements are sorted in ascending order, convert it to a *height-balanced* binary search tree.
Example 1:
1 | Input: nums = [-10,-3,0,5,9] |
1 | class Solution { |
在二叉树:构造二叉树登场! 和 二叉树:构造一棵最大的二叉树之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树。
其实思路也是一样的,不断中间分割,然后递归处理左区间,右区间,也可以说是分治。
此时相信大家应该对通过递归函数的返回值来增删二叉树很熟悉了,这也是常规操作。
在定义区间的过程中我们又一次强调了循环不变量的重要性。
最后依然给出迭代的方法,其实就是模拟取中间元素,然后不断分割去构造二叉树的过程。
538. Convert BST to Greater Tree
😭😍😄Medium
Given the root of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus the sum of all keys greater than the original key in BST.
As a reminder, a binary search tree is a tree that satisfies these constraints:
- The left subtree of a node contains only nodes with keys less than the node’s key.
- The right subtree of a node contains only nodes with keys greater than the node’s key.
- Both the left and right subtrees must also be binary search trees.
Example 1:
1 | Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] |
1 | class Solution { |
1 | // first attemp wrong: |
!!!!!!!!!!!!!因为
void travel(TreeNode node, int sum) 每次传进去的是一个integer, 每个loop是在单独对这个独立的(不同的)integer做修改,每个loop里的integer的地址都是不一样的。
但是如果把sum变成array,每次loop修改的是同一个地址里面的同一个数。
或者把sum从function parameter里面一出来变成class-level parameter,这样每次修改的也是同一个数!






























