Skip to content

Commit a4bbaef

Browse files
committed
二叉搜索树K值(四种解法, 需要掌握)
1 parent bef959b commit a4bbaef

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# coding: utf8
2+
3+
4+
"""
5+
题目链接: https://leetcode.com/problems/kth-smallest-element-in-a-bst/description.
6+
题目描述:
7+
8+
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
9+
10+
Note:
11+
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
12+
13+
Follow up:
14+
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How
15+
would you optimize the kthSmallest routine?
16+
17+
Credits:
18+
Special thanks to @ts for adding this problem and creating all test cases.
19+
20+
"""
21+
22+
23+
# Definition for a binary tree node.
24+
class TreeNode(object):
25+
def __init__(self, x):
26+
self.val = x
27+
self.left = None
28+
self.right = None
29+
30+
31+
class NewTreeNode(object):
32+
def __init__(self, x):
33+
self.val = x
34+
# 新增字段: 记录当前节点的左右子树节点数
35+
self.count = 1
36+
self.left = None
37+
self.right = None
38+
39+
40+
class Solution(object):
41+
def kthSmallest(self, root, k):
42+
"""
43+
:type root: TreeNode
44+
:type k: int
45+
:rtype: int
46+
"""
47+
self.k = k
48+
# return self.binary_search_tree_inorder_recursive_optimization(root)
49+
# ans = []
50+
# self.binary_search_tree_inorder_iterative(root, ans)
51+
# return ans[k - 1]
52+
# return self.binary_search_tree_inorder_iterative_optimization(root, k)
53+
# return self.binary_search_tree_conquer(root, k)
54+
root = self.reconstruct_tree(root)
55+
return self.binary_search_tree_conquer_optimization(root, k)
56+
57+
# 返回完整的中序序列, 需要额外数组空间存储
58+
def binary_search_tree_inorder_iterative(self, root, ans):
59+
stack = []
60+
while root or stack:
61+
while root:
62+
stack.append(root)
63+
root = root.left
64+
if stack:
65+
root = stack.pop()
66+
ans.append(root.val)
67+
root = root.right
68+
69+
# 计数, k时, 直接返回(递归)
70+
def binary_search_tree_inorder_recursive_optimization(self, root):
71+
if not root:
72+
return -1
73+
74+
val = self.binary_search_tree_inorder_recursive_optimization(root.left)
75+
if self.k == 0:
76+
return val
77+
self.k -= 1
78+
if self.k == 0:
79+
return root.val
80+
81+
return self.binary_search_tree_inorder_recursive_optimization(root.right)
82+
83+
# 计数, k时, 直接返回(非递归)
84+
def binary_search_tree_inorder_iterative_optimization(self, root, k):
85+
stack = []
86+
while root or stack:
87+
while root:
88+
stack.append(root)
89+
root = root.left
90+
if stack:
91+
root = stack.pop()
92+
k -= 1
93+
if k == 0:
94+
return root.val
95+
root = root.right
96+
97+
return -1
98+
99+
# 分治法: 计算左右子树节点数
100+
def binary_search_tree_conquer(self, root, k):
101+
if not root:
102+
return -1
103+
104+
nodes_num = self.calc_nodes(root.left)
105+
if k <= nodes_num:
106+
return self.binary_search_tree_conquer(root.left, k)
107+
elif k > nodes_num + 1:
108+
return self.binary_search_tree_conquer(root.right, k - nodes_num - 1)
109+
110+
return root.val
111+
112+
def calc_nodes(self, root):
113+
if not root:
114+
return 0
115+
116+
return 1 + self.calc_nodes(root.left) + self.calc_nodes(root.right)
117+
118+
# Follow up: 频繁修改节点, 频繁查找k小数值
119+
# 在上述的分治法基础上, 进行优化
120+
# 每次递归计算节点左右子树的节点数, 会造成不必要的开销
121+
# 可以考虑, 修改TreeNode, 新增count字段, 记录当前节点的左右子树节点数
122+
def binary_search_tree_conquer_optimization(self, root, k):
123+
if not root:
124+
return -1
125+
126+
if root.left:
127+
nodes_num = root.left.count
128+
if k <= nodes_num:
129+
return self.binary_search_tree_conquer_optimization(root.left, k)
130+
elif k > nodes_num + 1:
131+
return self.binary_search_tree_conquer_optimization(root.right, k - nodes_num - 1)
132+
133+
return root.val
134+
else:
135+
if k == 1:
136+
return root.val
137+
138+
return self.binary_search_tree_conquer_optimization(root.right, k - 1)
139+
140+
def reconstruct_tree(self, root):
141+
if not root:
142+
return None
143+
144+
left = self.reconstruct_tree(root.left)
145+
right = self.reconstruct_tree(root.right)
146+
root = NewTreeNode(root.val)
147+
root.left, root.right = left, right
148+
if root.left:
149+
root.count += root.left.count
150+
if root.right:
151+
root.count += root.right.count
152+
153+
return root

0 commit comments

Comments
 (0)