汇总了 LeetCode 及剑指 Offer 中关于二叉树的经典算法题目,涵盖左叶子之和、N 叉树层序遍历、路径总和、删除节点、找左下角值、最小绝对差、构造二叉树、累加树转换、直径计算、边界遍历、合并二叉树、最长同值路径、搜索与插入、距离 K 节点、范围求和、完全性检查、苹果收集、随机指针克隆、奇偶树判断、最近公共祖先、子树平均值、子结构判断、后序遍历验证、双向链表转换、平衡二叉树判断及下一个节点查找。提供 C++ 与 Python 代码实现及复杂度分析。
LinuxPan3 浏览
LeetCode
404. 左叶子之和 Sum of Left Leaves
题目
计算给定二叉树的所有左叶子之和。
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.
Record the values of left leaf nodes during the preorder traversal. In the recursive process, we use a flag from_left to record whether the current node is the left child node of the recursive node in the upper level.
classSolution {
public:
boolis_leaf(TreeNode* root){
if (!root) returnfalse;
return !root->left && !root->right;
}
intsumOfLeftLeaves(TreeNode* root){
if (!root) return0;
queue<TreeNode*> q;
q.push(root);
int res = 0;
while (!q.empty()) {
auto node = q.front(); q.pop();
if (node->left) {
if (is_leaf(node->left)) res += node->left->val;
else q.push(node->left);
}
if (node->right) {
if (!is_leaf(node->right)) q.push(node->right);
}
}
return res;
}
};
from collections import deque
classSolution:
defsumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
defis_leaf(root):
ifnot root: returnNonereturnnot root.left andnot root.right
q = deque()
q.append(root)
res = 0while q:
node = q.popleft()
if node.left:
if is_leaf(node.left): res += node.left.val
else: q.append(node.left)
if node.right:
ifnot is_leaf(node.right): q.append(node.right)
return res
复杂度
时间复杂度:O(n)
空间复杂度:O(n)
429. N-ary Tree Level Order Traversal
题目
Given an n-ary tree, return the level order traversal of its nodes' values.
Nary-Tree input serialization is represented in their level order traversal, each group of children is separated by the null value.
Given the root of a binary tree and an integer targetSum, return the number of paths where the sum of the values along the path equals targetSum.
The path does not need to start or end at the root or a leaf, but it must go downwards.
示例:root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
返回 3。和等于 8 的路径有:
Solve the problem by combining prefix sum with a hash map. The hash map records the cumulative sum of each path; if it is found that the current cumulative sum minus the target has appeared before, then there must be a path equal to the target in the previous path set.
classSolution {
public:
intpathSum(TreeNode* root, int targetSum){
m[0] = 1;
core(0, root, targetSum);
return res;
}
voidcore(long cur_sum, TreeNode* root, int targetSum){
if (!root) return;
cur_sum += root->val;
if (m.find(cur_sum - targetSum) != m.end()) {
res += m[cur_sum - targetSum];
}
++m[cur_sum];
core(cur_sum, root->left, targetSum);
core(cur_sum, root->right, targetSum);
--m[cur_sum];
}
private:
unordered_map<long, int> m;
int res = 0;
};
If the root value is larger than key, we need to do the recursion in left sub tree.
And if the root value is less than key, we need to do the recursion in right sub tree.
When the root value is equal to key, there are several cases to be handled:
If the root is a leaf, return None
If the root doesn't have left node, return root's right.
If the root doesn't have right node, return root's left.
The most complex case is that the root has both left and right node. We need to find the left-most node in root's right sub tree. Delete it and assign the value of this node to the root node.
classSolution {
public:
TreeNode* deleteNode(TreeNode* root, int key){
if (!root) returnnullptr;
if (root->val > key) { root->left = deleteNode(root->left, key); return root; }
if (root->val < key) { root->right = deleteNode(root->right, key); return root; }
if (!root->left && !root->right) returnnullptr;
if (!root->left) return root->right;
if (!root->right) return root->left;
TreeNode* succ = root->right;
while (succ->left) succ = succ->left;
root->right = deleteNode(root->right, succ->val);
root->val = succ->val;
return root;
}
};
classSolution {
public:
intfindBottomLeftValue(TreeNode* root){
queue<TreeNode*> q;
q.push(root);
int ret = 0;
while (!q.empty()) {
auto p = q.front(); q.pop();
if (p->right) q.push(p->right);
if (p->left) q.push(p->left);
ret = p->val;
}
return ret;
}
};
classSolution:
deffindBottomLeftValue(self, root: Optional[TreeNode]) -> int:
ifnot root: returnNone
q = queue.Queue()
q.put(root)
res = root.val
whilenot q.empty():
length = q.qsize()
for i inrange(length):
node = q.get()
if node.left: q.put(node.left)
if node.right: q.put(node.right)
if i == 0: res = node.val
return res
复杂度
时间:O(n)
空间:O(n)
530. Minimum Absolute Difference in BST
题目
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.
题解
中序遍历过程中记录最小差值。
classSolution {
public:
intminDiffInBST(TreeNode* root){
int res = INT_MAX;
stack<TreeNode*> stk;
bool flag = false;
int last = 0;
while (root || !stk.empty()) {
while (root) { stk.push(root); root = root->left; }
if (!stk.empty()) {
TreeNode* node = stk.top(); stk.pop();
if (flag && node->val - last < res) res = node->val - last;
root = node->right;
last = node->val;
flag = true;
}
}
return res;
}
};
import math
classSolution:
defminDiffInBST(self, root: Optional[TreeNode]) -> int:
flag = False
last_value = -1
res = math.inf
stk = []
while root orlen(stk) > 0:
while root:
stk.append(root)
root = root.left
node = stk.pop()
if flag: res = min(res, node.val - last_value)
root = node.right
flag = True
last_value = node.val
return res
递归形式
classSolution {
public:
voiddfs(TreeNode* root, int& pre, int& ans){
if (root == nullptr) return;
dfs(root->left, pre, ans);
if (pre != -1) ans = min(ans, root->val - pre);
pre = root->val;
dfs(root->right, pre, ans);
}
intminDiffInBST(TreeNode* root){
int ans = INT_MAX, pre = -1;
dfs(root, pre, ans);
return ans;
}
};
import math
classSolution:
defminDiffInBST(self, root: Optional[TreeNode]) -> int:
ans = math.inf
pre = -1defdfs(root):
nonlocal ans, pre
ifnot root: return
dfs(root.left)
if pre != -1: ans = min(ans, root.val - pre)
pre = root.val
dfs(root.right)
dfs(root)
return ans
复杂度
时间复杂度:O(n)
空间复杂度:O(n)
536. Construct Binary Tree from String
题目
You need to construct a binary tree from a string consisting of parenthesis and integers.
Input: s = "4(2(3)(1))(6(5))"
Output: [4,2,6,3,1,5]
题解
dfs + 栈 解决问题。
classSolution:
defgen_node(self, num, stk):
node = TreeNode(int(num)) if num elseNoneif stk:
ifnot stk[-1].left: stk[-1].left = node
elifnot stk[-1].right: stk[-1].right = node
if node: stk.append(node)
return''defstr2tree(self, s: str) -> Optional[TreeNode]:
num, stk = '', []
for i in s:
if i == '(': num = self.gen_node(num, stk)
elif i == ')': num = self.gen_node(num, stk); stk.pop()
else: num += i
return stk[-1] if stk elseNoneifnot s else TreeNode(int(s))
复杂度
Time Complexity: O(n)
Space Complexity: O(n)
538. 把二叉搜索树转换为累加树 Convert BST to Greater Tree
题目
给出二叉搜索树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
题解
反序二叉树中序遍历解决问题。
classSolution {
public:
TreeNode* convertBST(TreeNode* root){
if (root) {
convertBST(root->right);
sum += root->val;
root->val = sum;
convertBST(root->left);
}
return root;
}
private:
int sum = 0;
};
classSolution {
public:
TreeNode* convertBST(TreeNode* root){
int sum = 0;
stack<TreeNode*> stk;
auto cur = root;
while (!stk.empty() || cur) {
while (cur) { stk.push(cur); cur = cur->right; }
if (!stk.empty()) {
auto node = stk.top(); stk.pop();
sum += node->val;
node->val = sum;
cur = node->left;
}
}
return root;
}
};
classSolution:
defconvertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
cur = root
s = 0
stk = []
while cur orlen(stk) > 0:
while cur: stk.append(cur); cur = cur.right
node = stk.pop()
s += node.val
node.val = s
cur = node.left
return root
classSolution {
public:
intdiameterOfBinaryTree(TreeNode* root){
if (!root) return0;
unordered_map<TreeNode*, int> m;
int res = -1;
m[nullptr] = 0;
stack<TreeNode*> stk;
stk.push(root);
while (!stk.empty()) {
auto node = stk.top(); stk.pop();
if (m.count(node->left) && m.count(node->right)) {
m[node] = max(m[node->left], m[node->right]) + 1;
res = max(res, m[node->left] + m[node->right]);
} else {
stk.push(node);
if (node->right) stk.push(node->right);
if (node->left) stk.push(node->left);
}
}
return res;
}
};
classSolution:
defdiameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
ifnot root: return0
m = defaultdict(int)
m[None] = 0
stk = [root]
res = -1whilelen(stk) > 0:
node = stk.pop()
if node.left in m and node.right in m:
m[node] = max(m[node.left], m[node.right]) + 1
res = max(res, m[node.left] + m[node.right])
else:
stk.append(node)
if node.right: stk.append(node.right)
if node.left: stk.append(node.left)
return res
545. Boundary of Binary Tree
题目
The boundary of a binary tree is the concatenation of the root, the left boundary, the leaves ordered from left-to-right, and the reverse order of the right boundary.
Given the root of a binary tree, return the length of the longest path, where each node in the path has the same value.
题解
类似计算二叉树的直径。
classSolution:
def__init__(self):
self.res = 0deflongestUnivaluePath(self, root: Optional[TreeNode]) -> int:
self.core(root)
returnself.res
defcore(self, root):
ifnot root: return0
left = self.core(root.left)
right = self.core(root.right)
left = left + 1if root.left and root.left.val == root.val else0
right = right + 1if root.right and root.right.val == root.val else0self.res = max(self.res, left + right)
returnmax(left, right)
复杂度
Time Complexity: O(n)
Space Complexity: O(n)
700. 二叉搜索树中的搜索 Search in a Binary Search Tree
题目
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。返回以该节点为根的子树。如果节点不存在,则返回 null。
题解
二分遍历解决问题。
classSolution {
public:
TreeNode* searchBST(TreeNode* root, int val){
auto cur = root;
while (cur && cur->val != val) {
if (cur->val < val) cur = cur->right;
else cur = cur->left;
}
return cur;
}
};
783. 二叉搜索树节点最小距离 Minimum Distance Between BST Nodes
同 530
863. All Nodes Distance K in Binary Tree
题目
Given the root of a binary tree, the value of a target node target, and an integer k, return an array of the values of all nodes that have a distance k from the target node.
Given the root node of a binary search tree and two integers low and high, return the sum of values of all nodes with a value in the inclusive range [low, high].
1443. Minimum Time to Collect All Apples in a Tree
题目
Given an undirected tree consisting of n vertices numbered from 0 to n-1, which has some apples in their vertices. You spend 1 second to walk over one edge of the tree. Return the minimum time in seconds you have to spend to collect all apples in the tree, starting at vertex 0 and coming back to this vertex.
题解
classSolution:
defminTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int:
g = [[] for _ inrange(n)]
for x, y in edges: g[x].append(y); g[y].append(x)
defdfs(x, fa):
cost = 0for y in g[x]:
if y == fa: continue
y_cost = dfs(y, x)
if y_cost or hasApple[y]: cost += y_cost + 2return cost
return dfs(0, -1)
复杂度
Time Complexity: O(n)
Space Complexity: O(n)
1485. Clone Binary Tree With Random Pointer
题目
A binary tree is given such that each node contains an additional random pointer which could point to any node in the tree or null.
Return a deep copy of the tree.
题解
遍历过程中 fork,但需要记得重新构建 random 节点。
classSolution:
defcopyRandomBinaryTree(self, root: 'Node') -> 'NodeCopy':
d = {}
defdfs(r):
ifnot r: returnNone
new = NodeCopy(r.val)
new.left = dfs(r.left)
new.right = dfs(r.right)
new.random = None
d[r] = new
return new
t = dfs(root)
for k, v in d.items():
if k.random in d: v.random = d[k.random]
return t
1609. Even Odd Tree
题目
A binary tree is named Even-Odd if it meets the following conditions:
The root of the binary tree is at level index 0...
For every even-indexed level, all nodes at the level have odd integer values in strictly increasing order...
For every odd-indexed level, all nodes at the level have even integer values in strictly decreasing order...
输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(约定空树不是任意一个树的子结构)
B 是 A 的子结构,即 A 中有出现和 B 相同的结构和节点值。
题解
At first we need to find whether B is the sub structure of A and B's root is anchored to A's root. If it is yes, just return True. If it is no, we need to do the same thing to A's left and right recursively.
classSolution {
public:
boolis_sub(TreeNode* A, TreeNode* B){
if (!B) returntrue;
if (!A) returnfalse;
if (A->val != B->val) returnfalse;
returnis_sub(A->left, B->left) && is_sub(A->right, B->right);
}
boolisSubStructure(TreeNode* A, TreeNode* B){
if (A && B) {
if (is_sub(A, B)) returntrue;
returnisSubStructure(A->left, B) || isSubStructure(A->right, B);
}
returnfalse;
}
};
classSolution:
defis_sub(self, A, B):
ifnot B: returnTrueifnot A: returnFalseif A.val != B.val: returnFalsereturnself.is_sub(A.left, B.left) andself.is_sub(A.right, B.right)
defisSubStructure(self, A: Optional[TreeNode], B: Optional[TreeNode]) -> bool:
if A and B:
returnself.is_sub(A, B) orself.isSubStructure(A.left, B) orself.isSubStructure(A.right, B)
returnFalse
classSolution {
public:
boolverifyTreeOrder(vector<int>& postorder){
returndfs(postorder, 0, postorder.size() - 1);
}
booldfs(vector<int>& postorder, int i, int j){
if (i >= j) returntrue;
int p = i;
while (postorder[p] < postorder[j]) ++p;
int m = p;
while (postorder[p] > postorder[j]) ++p;
return p == j && dfs(postorder, i, m - 1) && dfs(postorder, m, j - 1);
}
};
classSolution:
defverifyTreeOrder(self, postorder: List[int]) -> bool:
iflen(postorder) <= 2: returnTruereturnself.core(postorder, 0, len(postorder) - 1)
defcore(self, postorder, left, right):
if left >= right: returnTrue
root_val = postorder[right]
idx = left
for i inrange(left, right + 1):
if postorder[i] >= root_val: idx = i; breakfor i inrange(idx, right + 1):
if postorder[i] <= root_val: breakreturn i == right andself.core(postorder, left, idx - 1) andself.core(postorder, idx, right - 1)
题解 2(栈)
classSolution {
public:
boolverifyTreeOrder(vector<int>& postorder){
stack<int> stk;
int parent = INT_MAX;
for (int i = postorder.size() - 1; i >= 0; --i) {
int cur = postorder[i];
while (!stk.empty() && stk.top() > cur) { parent = stk.top(); stk.pop(); }
if (cur > parent) returnfalse;
stk.push(cur);
}
returntrue;
}
};
LCR 155. 将二叉搜索树转化为排序的双向链表 E
题目
变换前:BST
变换后:双向循环链表
题解
Maintain pre and head during in-order traversal of the BST. We need to connect the head and tail node of the linked list after traversal.
classSolution {
public:
Node* treeToDoublyList(Node* root){
if (!root) returnnullptr;
core(root);
head->left = pre;
pre->right = head;
return head;
}
voidcore(Node* cur){
if (!cur) return;
core(cur->left);
if (pre) pre->right = cur;
else head = cur;
cur->left = pre;
pre = cur;
core(cur->right);
}
private:
Node* pre;
Node* head;
};
classSolution:
deftreeToDoublyList(self, root: 'Node') -> 'Node':
head = None
pre = Noneifnot root: return head
stk = []
while root orlen(stk) > 0:
while root: stk.append(root); root = root.left
node = stk.pop()
if pre: pre.right = node
else: head = node
node.left = pre
pre = node
root = node.right
head.left = pre
pre.right = head
return head