Skip to content

Commit 21e5c07

Browse files
committed
前缀树
1 parent caf7bbc commit 21e5c07

File tree

2 files changed

+484
-0
lines changed

2 files changed

+484
-0
lines changed

Diff for: leetcode算法之二叉搜索树.md

+351
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
今天来盘一盘 **二叉搜索树 ** 这类题目
2+
3+
4+
5+
使用**python**刷题分类整理的笔记,请参考: [https://github.com/lxztju/leetcode-algorithm/tree/v1](https://github.com/lxztju/leetcode-algorithm/tree/v1)
6+
7+
8+
9+
## 二叉搜索树
10+
二叉搜索树是指 **左子树的节点值均小于根节点的值, 右子树的节点值大于根节点的值(递归的概念,对于每个节点都成立)**
11+
12+
二叉搜索树的**中序遍历是排序数组**
13+
14+
15+
* 235 二叉搜索树的最近公共祖先 (Easy)
16+
* 108 将有序数组转换为二叉搜索树 (Easy)
17+
* 653 两数之和 IV - 输入 BST (Easy)
18+
* 530 二叉搜索树的最小绝对差 (Easy)
19+
* 501 二叉搜索树中的众数 (Easy)
20+
* 669 修剪二叉搜索树 (medium)
21+
* 230 二叉搜索树中第K小的元素 (Medium)
22+
* 538 把二叉搜索树转换为累加树 (medium)
23+
* 109 有序链表转换二叉搜索树 (Medium)
24+
* 236 二叉树的最近公共祖先 (Medium)
25+
26+
27+
28+
#### 235 二叉搜索树的最近公共祖先 (Easy)
29+
30+
* 如果当前节点值大于pq,那么说明分叉点存在于当前节点的左子树中
31+
* 如果当前节点值小于pq, 那么说明分叉点存在当前节点的右子树中
32+
* 否则,说明找到分叉点。
33+
34+
```c++
35+
class Solution {
36+
public:
37+
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
38+
if (root == nullptr) return nullptr;
39+
// 大于pq,搜索左子树
40+
if(root->val > p->val && root->val > q->val)
41+
return lowestCommonAncestor(root->left, p, q);
42+
// 小于pq,搜索右子树
43+
else if (root->val < p->val && root->val < q->val)
44+
return lowestCommonAncestor(root->right, p, q);
45+
// 找到分叉点。
46+
else
47+
return root;
48+
}
49+
};
50+
```
51+
52+
53+
#### 108 将有序数组转换为二叉搜索树 (Easy)
54+
* 二叉搜索树的**中序遍历是有序数组**
55+
* 根据这个性质,排序数组的中间元素是根节点,左半部分是左子树,右半部分是右子树,递归构建
56+
57+
```c++
58+
class Solution {
59+
public:
60+
TreeNode* sortedArrayToBST(vector<int>& nums) {
61+
return sortedArray2BST(nums, 0, nums.size()-1);
62+
}
63+
TreeNode* sortedArray2BST(vector<int>& nums, int left, int right){
64+
if (left > right) return nullptr;
65+
int middle = left + (right - left) / 2;
66+
TreeNode* root = new TreeNode(nums[middle]);
67+
root->left = sortedArray2BST(nums, left, middle-1);
68+
root->right = sortedArray2BST(nums, middle+1, right);
69+
return root;
70+
}
71+
};
72+
```
73+
74+
75+
76+
#### 653 两数之和 IV - 输入 BST (Easy)
77+
* 中序遍历得到排序数组
78+
* 然后双指针
79+
80+
```c++
81+
class Solution {
82+
public:
83+
bool findTarget(TreeNode* root, int k) {
84+
vector<int> nums;
85+
inorder(root, nums);
86+
int l = 0, r = nums.size() -1;
87+
while (l < r){
88+
int lrSum = nums[l] + nums[r];
89+
if (lrSum == k)
90+
return true;
91+
else if (lrSum > k)
92+
r--;
93+
else
94+
l++;
95+
}
96+
return false;
97+
}
98+
//中序遍历
99+
void inorder(TreeNode* root, vector<int>& nums){
100+
if (root == nullptr) return;
101+
inorder(root->left, nums);
102+
nums.push_back(root->val);
103+
inorder(root->right, nums);
104+
}
105+
};
106+
```
107+
108+
109+
110+
#### 530 二叉搜索树的最小绝对差 (Easy)
111+
* 依然利用中序遍历为有序数组的特点。
112+
113+
```c++
114+
class Solution {
115+
public:
116+
int getMinimumDifference(TreeNode* root) {
117+
vector<int> nums;
118+
inorder(root, nums);
119+
int res = nums[1] - nums[0];
120+
for (int i = 1; i < nums.size(); i++){
121+
res = min(res, nums[i] - nums[i-1]);
122+
}
123+
return res;
124+
}
125+
//中序遍历
126+
void inorder(TreeNode* root, vector<int>& nums){
127+
if (root == nullptr) return;
128+
inorder(root->left, nums);
129+
nums.push_back(root->val);
130+
inorder(root->right, nums);
131+
}
132+
};
133+
```
134+
135+
#### 501 二叉搜索树中的众数 (Easy)
136+
```c++
137+
class Solution {
138+
public:
139+
vector<int> findMode(TreeNode* root) {
140+
// 直接使用unordered_map,没有用到二叉搜索树的特定
141+
unordered_map<int, int> nodeFreq;
142+
vector<int> res;
143+
traversal(root, nodeFreq);
144+
int freq = 0;
145+
for (auto e = nodeFreq.begin(); e != nodeFreq.end(); e++){
146+
freq = max(freq, e->second);
147+
}
148+
for (auto e = nodeFreq.begin(); e != nodeFreq.end(); e++){
149+
if (e->second == freq)
150+
res.push_back(e->first);
151+
}
152+
return res;
153+
}
154+
void traversal(TreeNode* root, unordered_map<int, int>& nodeFreq){
155+
if (root == nullptr) return;
156+
nodeFreq[root->val]++;
157+
traversal(root->left, nodeFreq);
158+
traversal(root->right, nodeFreq);
159+
}
160+
};
161+
```
162+
163+
如果不使用额外的空间。
164+
* 针对二叉搜索树而言,其中序遍历是一个有序数组, 所有相等的元素均在一起出现
165+
* 利用cnt变量来统计当前元素出现的次数, maxcnt为最大频率的元素出现的次数,res保存众数
166+
167+
```c++
168+
class Solution {
169+
public:
170+
vector<int> findMode(TreeNode* root) {
171+
vector<int> res;
172+
int cnt = 1;
173+
int maxcnt = 1;
174+
int base;
175+
inorder(root, cnt, maxcnt, res, base);
176+
return res;
177+
}
178+
void inorder(TreeNode* root, int& cnt, int& maxcnt, vector<int>& res, int& base){
179+
if (root == nullptr) return;
180+
181+
inorder(root->left, cnt, maxcnt, res, base);
182+
183+
if (root->val == base){
184+
cnt++;
185+
}
186+
else{
187+
cnt = 1;
188+
base = root->val;
189+
}
190+
if (cnt > maxcnt){
191+
res.clear();
192+
res.push_back(base);
193+
maxcnt = cnt;
194+
}
195+
else if (cnt == maxcnt){
196+
res.push_back(base);
197+
}
198+
199+
inorder(root->right, cnt, maxcnt, res, base);
200+
}
201+
};
202+
```
203+
204+
#### 669 修剪二叉搜索树 (medium)
205+
206+
```c++
207+
class Solution {
208+
public:
209+
TreeNode* trimBST(TreeNode* root, int low, int high) {
210+
if(root == nullptr) return nullptr;
211+
if (root->val < low)
212+
return trimBST(root->right, low, high);
213+
else if (root->val > high)
214+
return trimBST(root->left, low, high);
215+
else{
216+
root->left = trimBST(root->left, low, high);
217+
root->right = trimBST(root->right, low, high);
218+
}
219+
return root;
220+
}
221+
};
222+
```
223+
224+
#### 230 二叉搜索树中第K小的元素 (Medium)
225+
226+
* 最直观的想法,二叉搜索树的中序遍历为排序数组
227+
```c++
228+
class Solution {
229+
public:
230+
int kthSmallest(TreeNode* root, int k) {
231+
vector<int> nums;
232+
inorder(root, nums);
233+
return nums[k-1];
234+
}
235+
236+
//中序遍历
237+
void inorder(TreeNode* root, vector<int>& nums){
238+
if (root == nullptr) return;
239+
inorder(root->left, nums);
240+
nums.push_back(root->val);
241+
inorder(root->right, nums);
242+
}
243+
};
244+
```
245+
246+
#### 538 把二叉搜索树转换为累加树 (medium)
247+
* 反中序遍历
248+
* 从最右侧看,根节点的值为根+=右子树的值
249+
* 左子树的值为左子树的值+=根的值
250+
251+
```c++
252+
class Solution {
253+
public:
254+
TreeNode* convertBST(TreeNode* root) {
255+
int val = 0;
256+
inverseInorder(root, val);
257+
return root;
258+
}
259+
// 反中序遍历
260+
void inverseInorder(TreeNode* root, int& val){
261+
if (root == nullptr) return;
262+
inverseInorder(root->right, val);
263+
val += root->val;
264+
root->val = val;
265+
inverseInorder(root->left, val);
266+
}
267+
};
268+
```
269+
270+
271+
#### 109 有序链表转换二叉搜索树 (Medium)
272+
* 有序链表转换为二叉搜索树与数组的转换方式基本一致
273+
* 只需要将链表分为左右两部分分别构成BST的左右子树即可
274+
275+
```c++
276+
class Solution {
277+
public:
278+
TreeNode* sortedListToBST(ListNode* head) {
279+
if (head == nullptr) return nullptr;
280+
// 返回链表中间节点的前驱节点
281+
ListNode* premiddle = premiddleList(head);
282+
cout<< (premiddle->val) << endl;
283+
// 链表的中间节点
284+
int val = 0;
285+
ListNode* middle = premiddle->next;
286+
if (middle == nullptr) {
287+
TreeNode* root = new TreeNode(premiddle->val);
288+
return root;
289+
}
290+
else{
291+
TreeNode* root = new TreeNode(middle->val);
292+
premiddle->next = nullptr;
293+
root->left = sortedListToBST(head);
294+
root->right = sortedListToBST(middle->next);
295+
return root;
296+
}
297+
}
298+
299+
300+
// 获得链表的中间节点的前一个节点。
301+
ListNode* premiddleList(ListNode* head){
302+
if ( head == nullptr) return nullptr;
303+
ListNode* slow = head;
304+
ListNode* pre = slow;
305+
ListNode* fast = head->next;
306+
while (fast != nullptr && fast->next != nullptr){
307+
pre = slow;
308+
slow = slow->next;
309+
fast = fast->next->next;
310+
}
311+
return pre;
312+
}
313+
};
314+
```
315+
316+
317+
#### 236 二叉树的最近公共祖先 (Medium)
318+
* 直接遍历查找,如果一棵树的左右子树中分别存在p与q,那么直接返回这个结点
319+
320+
```c++
321+
class Solution {
322+
public:
323+
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
324+
if (root == nullptr) return nullptr;
325+
if ( root == p || root == q) return root;
326+
TreeNode* left = lowestCommonAncestor(root->left, p, q);
327+
TreeNode* right = lowestCommonAncestor(root->right, p, q);
328+
if (left != nullptr && right != nullptr) return root;
329+
else if (left == nullptr)
330+
return right;
331+
else if (right == nullptr)
332+
return left;
333+
else return nullptr;
334+
}
335+
};
336+
```
337+
338+
339+
340+
341+
## 更多分类刷题资料
342+
343+
* 微信公众号: 小哲AI
344+
345+
![wechat_QRcode](https://img-blog.csdnimg.cn/20210104185413204.jpg)
346+
347+
* GitHub地址: [https://github.com/lxztju/leetcode-algorithm](https://github.com/lxztju/leetcode-algorithm)
348+
* csdn博客: [https://blog.csdn.net/lxztju](https://blog.csdn.net/lxztju)
349+
* 知乎专栏: [小哲AI](https://www.zhihu.com/column/c_1101089619118026752)
350+
* AI研习社专栏:[小哲AI](https://www.yanxishe.com/column/109)
351+

0 commit comments

Comments
 (0)