Leetcode 题解 - 树.md 30.9 KB
Newer Older
C
CyC2018 已提交
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39
<!-- GFM-TOC -->
* [递归](#递归)
    * [1. 树的高度](#1-树的高度)
    * [2. 平衡树](#2-平衡树)
    * [3. 两节点的最长路径](#3-两节点的最长路径)
    * [4. 翻转树](#4-翻转树)
    * [5. 归并两棵树](#5-归并两棵树)
    * [6. 判断路径和是否等于一个数](#6-判断路径和是否等于一个数)
    * [7. 统计路径和等于一个数的路径数量](#7-统计路径和等于一个数的路径数量)
    * [8. 子树](#8-子树)
    * [9. 树的对称](#9-树的对称)
    * [10. 最小路径](#10-最小路径)
    * [11. 统计左叶子节点的和](#11-统计左叶子节点的和)
    * [12. 相同节点值的最大路径长度](#12-相同节点值的最大路径长度)
    * [13. 间隔遍历](#13-间隔遍历)
    * [14. 找出二叉树中第二小的节点](#14-找出二叉树中第二小的节点)
* [层次遍历](#层次遍历)
    * [1. 一棵树每层节点的平均数](#1-一棵树每层节点的平均数)
    * [2. 得到左下角的节点](#2-得到左下角的节点)
* [前中后序遍历](#前中后序遍历)
    * [1. 非递归实现二叉树的前序遍历](#1-非递归实现二叉树的前序遍历)
    * [2. 非递归实现二叉树的后序遍历](#2-非递归实现二叉树的后序遍历)
    * [3. 非递归实现二叉树的中序遍历](#3-非递归实现二叉树的中序遍历)
* [BST](#bst)
    * [1. 修剪二叉查找树](#1-修剪二叉查找树)
    * [2. 寻找二叉查找树的第 k 个元素](#2-寻找二叉查找树的第-k-个元素)
    * [3. 把二叉查找树每个节点的值都加上比它大的节点的值](#3-把二叉查找树每个节点的值都加上比它大的节点的值)
    * [4. 二叉查找树的最近公共祖先](#4-二叉查找树的最近公共祖先)
    * [5. 二叉树的最近公共祖先](#5-二叉树的最近公共祖先)
    * [6. 从有序数组中构造二叉查找树](#6-从有序数组中构造二叉查找树)
    * [7. 根据有序链表构造平衡的二叉查找树](#7-根据有序链表构造平衡的二叉查找树)
    * [8. 在二叉查找树中寻找两个节点,使它们的和为一个给定值](#8-在二叉查找树中寻找两个节点,使它们的和为一个给定值)
    * [9. 在二叉查找树中查找两个节点之差的最小绝对值](#9-在二叉查找树中查找两个节点之差的最小绝对值)
    * [10. 寻找二叉查找树中出现次数最多的值](#10-寻找二叉查找树中出现次数最多的值)
* [Trie](#trie)
    * [1. 实现一个 Trie](#1-实现一个-trie)
    * [2. 实现一个 Trie,用来求前缀和](#2-实现一个-trie,用来求前缀和)
<!-- GFM-TOC -->

C
CyC2018 已提交
40 41

# 递归
C
CyC2018 已提交
42 43 44

一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。

C
CyC2018 已提交
45
## 1. 树的高度
C
CyC2018 已提交
46

C
CyC2018 已提交
47 48 49
104\. Maximum Depth of Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/)
C
CyC2018 已提交
50 51

```java
C
CyC2018 已提交
52 53 54
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
C
CyC2018 已提交
55 56 57
}
```

C
CyC2018 已提交
58
## 2. 平衡树
C
CyC2018 已提交
59

C
CyC2018 已提交
60 61 62
110\. Balanced Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/balanced-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/balanced-binary-tree/description/)
C
CyC2018 已提交
63 64

```html
C
CyC2018 已提交
65 66 67 68 69
    3
   / \
  9  20
    /  \
   15   7
C
CyC2018 已提交
70 71
```

C
CyC2018 已提交
72
平衡树左右子树高度差都小于等于 1
C
CyC2018 已提交
73 74

```java
C
CyC2018 已提交
75
private boolean result = true;
C
CyC2018 已提交
76

C
CyC2018 已提交
77 78 79
public boolean isBalanced(TreeNode root) {
    maxDepth(root);
    return result;
C
CyC2018 已提交
80 81
}

C
CyC2018 已提交
82 83 84 85 86 87
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    int l = maxDepth(root.left);
    int r = maxDepth(root.right);
    if (Math.abs(l - r) > 1) result = false;
    return 1 + Math.max(l, r);
C
CyC2018 已提交
88 89 90
}
```

C
CyC2018 已提交
91
## 3. 两节点的最长路径
C
CyC2018 已提交
92

C
CyC2018 已提交
93 94 95
543\. Diameter of Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/diameter-of-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/diameter-of-binary-tree/description/)
C
CyC2018 已提交
96 97 98 99

```html
Input:

C
CyC2018 已提交
100 101 102 103 104
         1
        / \
       2  3
      / \
     4   5
C
CyC2018 已提交
105

C
CyC2018 已提交
106
Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3].
C
CyC2018 已提交
107 108 109
```

```java
C
CyC2018 已提交
110
private int max = 0;
C
CyC2018 已提交
111

C
CyC2018 已提交
112 113 114
public int diameterOfBinaryTree(TreeNode root) {
    depth(root);
    return max;
C
CyC2018 已提交
115 116
}

C
CyC2018 已提交
117 118 119 120 121 122
private int depth(TreeNode root) {
    if (root == null) return 0;
    int leftDepth = depth(root.left);
    int rightDepth = depth(root.right);
    max = Math.max(max, leftDepth + rightDepth);
    return Math.max(leftDepth, rightDepth) + 1;
C
CyC2018 已提交
123 124 125
}
```

C
CyC2018 已提交
126
## 4. 翻转树
C
CyC2018 已提交
127

C
CyC2018 已提交
128 129 130
226\. Invert Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/invert-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/invert-binary-tree/description/)
C
CyC2018 已提交
131 132

```java
C
CyC2018 已提交
133 134 135 136 137 138
public TreeNode invertTree(TreeNode root) {
    if (root == null) return null;
    TreeNode left = root.left;  // 后面的操作会改变 left 指针,因此先保存下来
    root.left = invertTree(root.right);
    root.right = invertTree(left);
    return root;
C
CyC2018 已提交
139 140 141
}
```

C
CyC2018 已提交
142
## 5. 归并两棵树
C
CyC2018 已提交
143

C
CyC2018 已提交
144 145 146
617\. Merge Two Binary Trees (Easy)

[Leetcode](https://leetcode.com/problems/merge-two-binary-trees/description/) / [力扣](https://leetcode-cn.com/problems/merge-two-binary-trees/description/)
C
CyC2018 已提交
147 148 149

```html
Input:
C
CyC2018 已提交
150 151 152 153 154 155
       Tree 1                     Tree 2
          1                         2
         / \                       / \
        3   2                     1   3
       /                           \   \
      5                             4   7
C
CyC2018 已提交
156 157

Output:
C
CyC2018 已提交
158 159 160 161 162
         3
        / \
       4   5
      / \   \
     5   4   7
C
CyC2018 已提交
163 164 165
```

```java
C
CyC2018 已提交
166 167 168 169 170 171 172 173
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
    if (t1 == null && t2 == null) return null;
    if (t1 == null) return t2;
    if (t2 == null) return t1;
    TreeNode root = new TreeNode(t1.val + t2.val);
    root.left = mergeTrees(t1.left, t2.left);
    root.right = mergeTrees(t1.right, t2.right);
    return root;
C
CyC2018 已提交
174 175 176
}
```

C
CyC2018 已提交
177
## 6. 判断路径和是否等于一个数
C
CyC2018 已提交
178

C
CyC2018 已提交
179 180 181
Leetcdoe : 112. Path Sum (Easy)

[Leetcode](https://leetcode.com/problems/path-sum/description/) / [力扣](https://leetcode-cn.com/problems/path-sum/description/)
C
CyC2018 已提交
182 183

```html
C
CyC2018 已提交
184
Given the below binary tree and sum = 22,
C
CyC2018 已提交
185

C
CyC2018 已提交
186 187 188 189 190 191 192
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
C
CyC2018 已提交
193

C
CyC2018 已提交
194
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
C
CyC2018 已提交
195 196
```

C
CyC2018 已提交
197
路径和定义为从 root 到 leaf 的所有节点的和。
C
CyC2018 已提交
198 199

```java
C
CyC2018 已提交
200 201 202 203
public boolean hasPathSum(TreeNode root, int sum) {
    if (root == null) return false;
    if (root.left == null && root.right == null && root.val == sum) return true;
    return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
C
CyC2018 已提交
204 205 206
}
```

C
CyC2018 已提交
207
## 7. 统计路径和等于一个数的路径数量
C
CyC2018 已提交
208

C
CyC2018 已提交
209 210 211
437\. Path Sum III (Easy)

[Leetcode](https://leetcode.com/problems/path-sum-iii/description/) / [力扣](https://leetcode-cn.com/problems/path-sum-iii/description/)
C
CyC2018 已提交
212 213

```html
C
CyC2018 已提交
214
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
C
CyC2018 已提交
215

C
CyC2018 已提交
216 217 218 219 220 221 222
      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1
C
CyC2018 已提交
223

C
CyC2018 已提交
224
Return 3. The paths that sum to 8 are:
C
CyC2018 已提交
225

C
CyC2018 已提交
226 227 228
1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11
C
CyC2018 已提交
229 230
```

C
CyC2018 已提交
231
路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续。
C
CyC2018 已提交
232 233

```java
C
CyC2018 已提交
234 235 236 237
public int pathSum(TreeNode root, int sum) {
    if (root == null) return 0;
    int ret = pathSumStartWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
    return ret;
C
CyC2018 已提交
238 239
}

C
CyC2018 已提交
240 241 242 243 244 245
private int pathSumStartWithRoot(TreeNode root, int sum) {
    if (root == null) return 0;
    int ret = 0;
    if (root.val == sum) ret++;
    ret += pathSumStartWithRoot(root.left, sum - root.val) + pathSumStartWithRoot(root.right, sum - root.val);
    return ret;
C
CyC2018 已提交
246 247 248
}
```

C
CyC2018 已提交
249
## 8. 子树
C
CyC2018 已提交
250

C
CyC2018 已提交
251 252 253
572\. Subtree of Another Tree (Easy)

[Leetcode](https://leetcode.com/problems/subtree-of-another-tree/description/) / [力扣](https://leetcode-cn.com/problems/subtree-of-another-tree/description/)
C
CyC2018 已提交
254 255

```html
C
CyC2018 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
Given tree s:
     3
    / \
   4   5
  / \
 1   2

Given tree t:
   4
  / \
 1   2

Return true, because t has the same structure and node values with a subtree of s.

Given tree s:

     3
    / \
   4   5
  / \
 1   2
    /
   0

Given tree t:
   4
  / \
 1   2

Return false.
C
CyC2018 已提交
286 287 288
```

```java
C
CyC2018 已提交
289 290 291
public boolean isSubtree(TreeNode s, TreeNode t) {
    if (s == null) return false;
    return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
C
CyC2018 已提交
292 293
}

C
CyC2018 已提交
294 295 296 297 298
private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
    if (t == null && s == null) return true;
    if (t == null || s == null) return false;
    if (t.val != s.val) return false;
    return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
C
CyC2018 已提交
299 300 301
}
```

C
CyC2018 已提交
302
## 9. 树的对称
C
CyC2018 已提交
303

C
CyC2018 已提交
304 305 306
101\. Symmetric Tree (Easy)

[Leetcode](https://leetcode.com/problems/symmetric-tree/description/) / [力扣](https://leetcode-cn.com/problems/symmetric-tree/description/)
C
CyC2018 已提交
307 308

```html
C
CyC2018 已提交
309 310 311 312 313
    1
   / \
  2   2
 / \ / \
3  4 4  3
C
CyC2018 已提交
314 315 316
```

```java
C
CyC2018 已提交
317 318 319
public boolean isSymmetric(TreeNode root) {
    if (root == null) return true;
    return isSymmetric(root.left, root.right);
C
CyC2018 已提交
320 321
}

C
CyC2018 已提交
322 323 324 325 326
private boolean isSymmetric(TreeNode t1, TreeNode t2) {
    if (t1 == null && t2 == null) return true;
    if (t1 == null || t2 == null) return false;
    if (t1.val != t2.val) return false;
    return isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left);
C
CyC2018 已提交
327 328 329
}
```

C
CyC2018 已提交
330
## 10. 最小路径
C
CyC2018 已提交
331

C
CyC2018 已提交
332 333 334
111\. Minimum Depth of Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/minimum-depth-of-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/description/)
C
CyC2018 已提交
335 336 337 338

树的根节点到叶子节点的最小路径长度

```java
C
CyC2018 已提交
339 340 341 342 343 344
public int minDepth(TreeNode root) {
    if (root == null) return 0;
    int left = minDepth(root.left);
    int right = minDepth(root.right);
    if (left == 0 || right == 0) return left + right + 1;
    return Math.min(left, right) + 1;
C
CyC2018 已提交
345 346 347
}
```

C
CyC2018 已提交
348
## 11. 统计左叶子节点的和
C
CyC2018 已提交
349

C
CyC2018 已提交
350 351 352
404\. Sum of Left Leaves (Easy)

[Leetcode](https://leetcode.com/problems/sum-of-left-leaves/description/) / [力扣](https://leetcode-cn.com/problems/sum-of-left-leaves/description/)
C
CyC2018 已提交
353 354

```html
C
CyC2018 已提交
355 356 357 358 359
    3
   / \
  9  20
    /  \
   15   7
C
CyC2018 已提交
360

C
CyC2018 已提交
361
There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.
C
CyC2018 已提交
362 363 364
```

```java
C
CyC2018 已提交
365 366 367 368
public int sumOfLeftLeaves(TreeNode root) {
    if (root == null) return 0;
    if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
    return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
C
CyC2018 已提交
369 370
}

C
CyC2018 已提交
371 372 373
private boolean isLeaf(TreeNode node){
    if (node == null) return false;
    return node.left == null && node.right == null;
C
CyC2018 已提交
374 375 376
}
```

C
CyC2018 已提交
377
## 12. 相同节点值的最大路径长度
C
CyC2018 已提交
378

C
CyC2018 已提交
379 380 381
687\. Longest Univalue Path (Easy)

[Leetcode](https://leetcode.com/problems/longest-univalue-path/) / [力扣](https://leetcode-cn.com/problems/longest-univalue-path/)
C
CyC2018 已提交
382 383

```html
C
CyC2018 已提交
384 385 386 387 388
             1
            / \
           4   5
          / \   \
         4   4   5
C
CyC2018 已提交
389

C
CyC2018 已提交
390
Output : 2
C
CyC2018 已提交
391 392 393
```

```java
C
CyC2018 已提交
394
private int path = 0;
C
CyC2018 已提交
395

C
CyC2018 已提交
396 397 398
public int longestUnivaluePath(TreeNode root) {
    dfs(root);
    return path;
C
CyC2018 已提交
399 400
}

C
CyC2018 已提交
401 402 403 404 405 406 407 408
private int dfs(TreeNode root){
    if (root == null) return 0;
    int left = dfs(root.left);
    int right = dfs(root.right);
    int leftPath = root.left != null && root.left.val == root.val ? left + 1 : 0;
    int rightPath = root.right != null && root.right.val == root.val ? right + 1 : 0;
    path = Math.max(path, leftPath + rightPath);
    return Math.max(leftPath, rightPath);
C
CyC2018 已提交
409 410 411
}
```

C
CyC2018 已提交
412
## 13. 间隔遍历
C
CyC2018 已提交
413

C
CyC2018 已提交
414 415 416
337\. House Robber III (Medium)

[Leetcode](https://leetcode.com/problems/house-robber-iii/description/) / [力扣](https://leetcode-cn.com/problems/house-robber-iii/description/)
C
CyC2018 已提交
417 418

```html
C
CyC2018 已提交
419 420 421 422 423 424
     3
    / \
   2   3
    \   \
     3   1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
C
CyC2018 已提交
425 426 427
```

```java
C
CyC2018 已提交
428 429 430 431 432 433 434
public int rob(TreeNode root) {
    if (root == null) return 0;
    int val1 = root.val;
    if (root.left != null) val1 += rob(root.left.left) + rob(root.left.right);
    if (root.right != null) val1 += rob(root.right.left) + rob(root.right.right);
    int val2 = rob(root.left) + rob(root.right);
    return Math.max(val1, val2);
C
CyC2018 已提交
435 436 437
}
```

C
CyC2018 已提交
438
## 14. 找出二叉树中第二小的节点
C
CyC2018 已提交
439

C
CyC2018 已提交
440 441 442
671\. Second Minimum Node In a Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree/description/)
C
CyC2018 已提交
443 444 445

```html
Input:
C
CyC2018 已提交
446 447 448 449 450
   2
  / \
 2   5
    / \
    5  7
C
CyC2018 已提交
451

C
CyC2018 已提交
452
Output: 5
C
CyC2018 已提交
453 454
```

C
CyC2018 已提交
455
一个节点要么具有 0 个或 2 个子节点,如果有子节点,那么根节点是最小的节点。
C
CyC2018 已提交
456 457

```java
C
CyC2018 已提交
458 459 460 461 462 463 464 465 466 467
public int findSecondMinimumValue(TreeNode root) {
    if (root == null) return -1;
    if (root.left == null && root.right == null) return -1;
    int leftVal = root.left.val;
    int rightVal = root.right.val;
    if (leftVal == root.val) leftVal = findSecondMinimumValue(root.left);
    if (rightVal == root.val) rightVal = findSecondMinimumValue(root.right);
    if (leftVal != -1 && rightVal != -1) return Math.min(leftVal, rightVal);
    if (leftVal != -1) return leftVal;
    return rightVal;
C
CyC2018 已提交
468 469 470
}
```

C
CyC2018 已提交
471
# 层次遍历
C
CyC2018 已提交
472

C
CyC2018 已提交
473
使用 BFS 进行层次遍历。不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。
C
CyC2018 已提交
474

C
CyC2018 已提交
475
## 1. 一棵树每层节点的平均数
C
CyC2018 已提交
476

C
CyC2018 已提交
477 478 479
637\. Average of Levels in Binary Tree (Easy)

[Leetcode](https://leetcode.com/problems/average-of-levels-in-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/description/)
C
CyC2018 已提交
480 481

```java
C
CyC2018 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
public List<Double> averageOfLevels(TreeNode root) {
    List<Double> ret = new ArrayList<>();
    if (root == null) return ret;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        int cnt = queue.size();
        double sum = 0;
        for (int i = 0; i < cnt; i++) {
            TreeNode node = queue.poll();
            sum += node.val;
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);
        }
        ret.add(sum / cnt);
    }
    return ret;
C
CyC2018 已提交
499 500 501
}
```

C
CyC2018 已提交
502
## 2. 得到左下角的节点
C
CyC2018 已提交
503

C
CyC2018 已提交
504 505 506
513\. Find Bottom Left Tree Value (Easy)

[Leetcode](https://leetcode.com/problems/find-bottom-left-tree-value/description/) / [力扣](https://leetcode-cn.com/problems/find-bottom-left-tree-value/description/)
C
CyC2018 已提交
507 508 509 510

```html
Input:

C
CyC2018 已提交
511 512 513 514 515 516 517
        1
       / \
      2   3
     /   / \
    4   5   6
       /
      7
C
CyC2018 已提交
518 519 520 521 522 523

Output:
7
```

```java
C
CyC2018 已提交
524 525 526 527 528 529 530 531 532
public int findBottomLeftValue(TreeNode root) {
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        root = queue.poll();
        if (root.right != null) queue.add(root.right);
        if (root.left != null) queue.add(root.left);
    }
    return root.val;
C
CyC2018 已提交
533 534 535
}
```

C
CyC2018 已提交
536
# 前中后序遍历
C
CyC2018 已提交
537 538

```html
C
CyC2018 已提交
539 540 541 542 543
    1
   / \
  2   3
 / \   \
4   5   6
C
CyC2018 已提交
544 545
```

C
CyC2018 已提交
546 547 548 549
- 层次遍历顺序:[1 2 3 4 5 6]
- 前序遍历顺序:[1 2 4 5 3 6]
- 中序遍历顺序:[4 2 5 1 3 6]
- 后序遍历顺序:[4 5 2 6 3 1]
C
CyC2018 已提交
550

C
CyC2018 已提交
551
层次遍历使用 BFS 实现,利用的就是 BFS 一层一层遍历的特性;而前序、中序、后序遍历利用了 DFS 实现。
C
CyC2018 已提交
552 553 554

前序、中序、后序遍只是在对节点访问的顺序有一点不同,其它都相同。

C
CyC2018 已提交
555
① 前序
C
CyC2018 已提交
556 557

```java
C
CyC2018 已提交
558 559 560 561
void dfs(TreeNode root) {
    visit(root);
    dfs(root.left);
    dfs(root.right);
C
CyC2018 已提交
562 563 564
}
```

C
CyC2018 已提交
565
② 中序
C
CyC2018 已提交
566 567

```java
C
CyC2018 已提交
568 569 570 571
void dfs(TreeNode root) {
    dfs(root.left);
    visit(root);
    dfs(root.right);
C
CyC2018 已提交
572 573 574
}
```

C
CyC2018 已提交
575
③ 后序
C
CyC2018 已提交
576 577

```java
C
CyC2018 已提交
578 579 580 581
void dfs(TreeNode root) {
    dfs(root.left);
    dfs(root.right);
    visit(root);
C
CyC2018 已提交
582 583 584
}
```

C
CyC2018 已提交
585
## 1. 非递归实现二叉树的前序遍历
C
CyC2018 已提交
586

C
CyC2018 已提交
587 588 589
144\. Binary Tree Preorder Traversal (Medium)

[Leetcode](https://leetcode.com/problems/binary-tree-preorder-traversal/description/) / [力扣](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/description/)
C
CyC2018 已提交
590 591

```java
C
CyC2018 已提交
592 593 594 595 596 597 598 599 600 601 602 603
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        if (node == null) continue;
        ret.add(node.val);
        stack.push(node.right);  // 先右后左,保证左子树先遍历
        stack.push(node.left);
    }
    return ret;
C
CyC2018 已提交
604 605 606
}
```

C
CyC2018 已提交
607
## 2. 非递归实现二叉树的后序遍历
C
CyC2018 已提交
608

C
CyC2018 已提交
609 610 611
145\. Binary Tree Postorder Traversal (Medium)

[Leetcode](https://leetcode.com/problems/binary-tree-postorder-traversal/description/) / [力扣](https://leetcode-cn.com/problems/binary-tree-postorder-traversal/description/)
C
CyC2018 已提交
612

C
CyC2018 已提交
613
前序遍历为 root -> left -> right,后序遍历为 left -> right -> root。可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反。
C
CyC2018 已提交
614 615

```java
C
CyC2018 已提交
616 617 618 619 620 621 622 623 624 625 626 627 628
public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        if (node == null) continue;
        ret.add(node.val);
        stack.push(node.left);
        stack.push(node.right);
    }
    Collections.reverse(ret);
    return ret;
C
CyC2018 已提交
629 630 631
}
```

C
CyC2018 已提交
632
## 3. 非递归实现二叉树的中序遍历
C
CyC2018 已提交
633

C
CyC2018 已提交
634 635 636
94\. Binary Tree Inorder Traversal (Medium)

[Leetcode](https://leetcode.com/problems/binary-tree-inorder-traversal/description/) / [力扣](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/description/)
C
CyC2018 已提交
637 638

```java
C
CyC2018 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    if (root == null) return ret;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        TreeNode node = stack.pop();
        ret.add(node.val);
        cur = node.right;
    }
    return ret;
C
CyC2018 已提交
654 655 656
}
```

C
CyC2018 已提交
657
# BST
C
CyC2018 已提交
658 659 660 661 662

二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。

二叉查找树中序遍历有序。

C
CyC2018 已提交
663
## 1. 修剪二叉查找树
C
CyC2018 已提交
664

C
CyC2018 已提交
665 666 667
669\. Trim a Binary Search Tree (Easy)

[Leetcode](https://leetcode.com/problems/trim-a-binary-search-tree/description/) / [力扣](https://leetcode-cn.com/problems/trim-a-binary-search-tree/description/)
C
CyC2018 已提交
668 669 670 671

```html
Input:

C
CyC2018 已提交
672 673 674 675 676 677 678
    3
   / \
  0   4
   \
    2
   /
  1
C
CyC2018 已提交
679

C
CyC2018 已提交
680 681
  L = 1
  R = 3
C
CyC2018 已提交
682 683 684

Output:

C
CyC2018 已提交
685 686 687 688 689
      3
     /
   2
  /
 1
C
CyC2018 已提交
690 691
```

C
CyC2018 已提交
692
题目描述:只保留值在 L \~ R 之间的节点
C
CyC2018 已提交
693 694

```java
C
CyC2018 已提交
695 696 697 698 699 700 701
public TreeNode trimBST(TreeNode root, int L, int R) {
    if (root == null) return null;
    if (root.val > R) return trimBST(root.left, L, R);
    if (root.val < L) return trimBST(root.right, L, R);
    root.left = trimBST(root.left, L, R);
    root.right = trimBST(root.right, L, R);
    return root;
C
CyC2018 已提交
702 703 704
}
```

C
CyC2018 已提交
705
## 2. 寻找二叉查找树的第 k 个元素
C
CyC2018 已提交
706

C
CyC2018 已提交
707 708 709
230\. Kth Smallest Element in a BST (Medium)

[Leetcode](https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/) / [力扣](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/description/)
C
CyC2018 已提交
710 711 712 713 714


中序遍历解法:

```java
C
CyC2018 已提交
715 716
private int cnt = 0;
private int val;
C
CyC2018 已提交
717

C
CyC2018 已提交
718 719 720
public int kthSmallest(TreeNode root, int k) {
    inOrder(root, k);
    return val;
C
CyC2018 已提交
721 722
}

C
CyC2018 已提交
723 724 725 726 727 728 729 730 731
private void inOrder(TreeNode node, int k) {
    if (node == null) return;
    inOrder(node.left, k);
    cnt++;
    if (cnt == k) {
        val = node.val;
        return;
    }
    inOrder(node.right, k);
C
CyC2018 已提交
732 733 734 735 736 737
}
```

递归解法:

```java
C
CyC2018 已提交
738 739 740 741 742
public int kthSmallest(TreeNode root, int k) {
    int leftCnt = count(root.left);
    if (leftCnt == k - 1) return root.val;
    if (leftCnt > k - 1) return kthSmallest(root.left, k);
    return kthSmallest(root.right, k - leftCnt - 1);
C
CyC2018 已提交
743 744
}

C
CyC2018 已提交
745 746 747
private int count(TreeNode node) {
    if (node == null) return 0;
    return 1 + count(node.left) + count(node.right);
C
CyC2018 已提交
748 749 750
}
```

C
CyC2018 已提交
751
## 3. 把二叉查找树每个节点的值都加上比它大的节点的值
C
CyC2018 已提交
752

C
CyC2018 已提交
753 754 755
Convert BST to Greater Tree (Easy)

[Leetcode](https://leetcode.com/problems/convert-bst-to-greater-tree/description/) / [力扣](https://leetcode-cn.com/problems/convert-bst-to-greater-tree/description/)
C
CyC2018 已提交
756 757

```html
C
CyC2018 已提交
758
Input: The root of a Binary Search Tree like this:
C
CyC2018 已提交
759

C
CyC2018 已提交
760 761 762
              5
            /   \
           2     13
C
CyC2018 已提交
763

C
CyC2018 已提交
764
Output: The root of a Greater Tree like this:
C
CyC2018 已提交
765

C
CyC2018 已提交
766 767 768
             18
            /   \
          20     13
C
CyC2018 已提交
769 770 771 772 773
```

先遍历右子树。

```java
C
CyC2018 已提交
774
private int sum = 0;
C
CyC2018 已提交
775

C
CyC2018 已提交
776 777 778
public TreeNode convertBST(TreeNode root) {
    traver(root);
    return root;
C
CyC2018 已提交
779 780
}

C
CyC2018 已提交
781 782 783 784 785 786
private void traver(TreeNode node) {
    if (node == null) return;
    traver(node.right);
    sum += node.val;
    node.val = sum;
    traver(node.left);
C
CyC2018 已提交
787 788 789
}
```

C
CyC2018 已提交
790
## 4. 二叉查找树的最近公共祖先
C
CyC2018 已提交
791

C
CyC2018 已提交
792 793 794
235\. Lowest Common Ancestor of a Binary Search Tree (Easy)

[Leetcode](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/) / [力扣](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/)
C
CyC2018 已提交
795 796

```html
C
CyC2018 已提交
797 798 799 800 801 802 803 804 805
        _______6______
      /                \
  ___2__             ___8__
 /      \           /      \
0        4         7        9
        /  \
       3   5

For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
C
CyC2018 已提交
806 807 808
```

```java
C
CyC2018 已提交
809 810 811 812
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
    if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
    return root;
C
CyC2018 已提交
813 814 815
}
```

C
CyC2018 已提交
816
## 5. 二叉树的最近公共祖先
C
CyC2018 已提交
817

C
CyC2018 已提交
818 819 820
236\. Lowest Common Ancestor of a Binary Tree (Medium) 

[Leetcode](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/) / [力扣](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/description/)
C
CyC2018 已提交
821 822

```html
C
CyC2018 已提交
823 824 825 826 827 828 829 830 831
       _______3______
      /              \
  ___5__           ___1__
 /      \         /      \
6        2       0        8
        /  \
       7    4

For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.
C
CyC2018 已提交
832 833 834
```

```java
C
CyC2018 已提交
835 836 837 838 839
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root == null || root == p || root == q) return root;
    TreeNode left = lowestCommonAncestor(root.left, p, q);
    TreeNode right = lowestCommonAncestor(root.right, p, q);
    return left == null ? right : right == null ? left : root;
C
CyC2018 已提交
840 841 842
}
```

C
CyC2018 已提交
843
## 6. 从有序数组中构造二叉查找树
C
CyC2018 已提交
844

C
CyC2018 已提交
845 846 847
108\. Convert Sorted Array to Binary Search Tree (Easy)

[Leetcode](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/) / [力扣](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/description/)
C
CyC2018 已提交
848 849

```java
C
CyC2018 已提交
850 851
public TreeNode sortedArrayToBST(int[] nums) {
    return toBST(nums, 0, nums.length - 1);
C
CyC2018 已提交
852 853
}

C
CyC2018 已提交
854 855 856 857 858 859 860
private TreeNode toBST(int[] nums, int sIdx, int eIdx){
    if (sIdx > eIdx) return null;
    int mIdx = (sIdx + eIdx) / 2;
    TreeNode root = new TreeNode(nums[mIdx]);
    root.left =  toBST(nums, sIdx, mIdx - 1);
    root.right = toBST(nums, mIdx + 1, eIdx);
    return root;
C
CyC2018 已提交
861 862 863
}
```

C
CyC2018 已提交
864
## 7. 根据有序链表构造平衡的二叉查找树
C
CyC2018 已提交
865

C
CyC2018 已提交
866 867 868
109\. Convert Sorted List to Binary Search Tree (Medium)

[Leetcode](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/description/) / [力扣](https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/description/)
C
CyC2018 已提交
869 870

```html
C
CyC2018 已提交
871
Given the sorted linked list: [-10,-3,0,5,9],
C
CyC2018 已提交
872

C
CyC2018 已提交
873
One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
C
CyC2018 已提交
874

C
CyC2018 已提交
875 876 877 878 879
      0
     / \
   -3   9
   /   /
 -10  5
C
CyC2018 已提交
880 881 882
```

```java
C
CyC2018 已提交
883 884 885 886 887 888 889 890 891 892
public TreeNode sortedListToBST(ListNode head) {
    if (head == null) return null;
    if (head.next == null) return new TreeNode(head.val);
    ListNode preMid = preMid(head);
    ListNode mid = preMid.next;
    preMid.next = null;  // 断开链表
    TreeNode t = new TreeNode(mid.val);
    t.left = sortedListToBST(head);
    t.right = sortedListToBST(mid.next);
    return t;
C
CyC2018 已提交
893 894
}

C
CyC2018 已提交
895 896 897 898 899 900 901 902 903
private ListNode preMid(ListNode head) {
    ListNode slow = head, fast = head.next;
    ListNode pre = head;
    while (fast != null && fast.next != null) {
        pre = slow;
        slow = slow.next;
        fast = fast.next.next;
    }
    return pre;
C
CyC2018 已提交
904 905 906
}
```

C
CyC2018 已提交
907
## 8. 在二叉查找树中寻找两个节点,使它们的和为一个给定值
C
CyC2018 已提交
908

C
CyC2018 已提交
909 910 911
653\. Two Sum IV - Input is a BST (Easy)

[Leetcode](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/description/) / [力扣](https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/description/)
C
CyC2018 已提交
912 913 914 915

```html
Input:

C
CyC2018 已提交
916 917 918 919 920
    5
   / \
  3   6
 / \   \
2   4   7
C
CyC2018 已提交
921

C
CyC2018 已提交
922
Target = 9
C
CyC2018 已提交
923

C
CyC2018 已提交
924
Output: True
C
CyC2018 已提交
925 926 927 928 929 930 931
```

使用中序遍历得到有序数组之后,再利用双指针对数组进行查找。

应该注意到,这一题不能用分别在左右子树两部分来处理这种思想,因为两个待求的节点可能分别在左右子树中。

```java
C
CyC2018 已提交
932 933 934 935 936 937 938 939 940 941 942
public boolean findTarget(TreeNode root, int k) {
    List<Integer> nums = new ArrayList<>();
    inOrder(root, nums);
    int i = 0, j = nums.size() - 1;
    while (i < j) {
        int sum = nums.get(i) + nums.get(j);
        if (sum == k) return true;
        if (sum < k) i++;
        else j--;
    }
    return false;
C
CyC2018 已提交
943 944
}

C
CyC2018 已提交
945 946 947 948 949
private void inOrder(TreeNode root, List<Integer> nums) {
    if (root == null) return;
    inOrder(root.left, nums);
    nums.add(root.val);
    inOrder(root.right, nums);
C
CyC2018 已提交
950 951 952
}
```

C
CyC2018 已提交
953
## 9. 在二叉查找树中查找两个节点之差的最小绝对值
C
CyC2018 已提交
954

C
CyC2018 已提交
955 956 957
530\. Minimum Absolute Difference in BST (Easy)

[Leetcode](https://leetcode.com/problems/minimum-absolute-difference-in-bst/description/) / [力扣](https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/description/)
C
CyC2018 已提交
958 959 960 961

```html
Input:

C
CyC2018 已提交
962 963 964 965 966
   1
    \
     3
    /
   2
C
CyC2018 已提交
967 968 969 970 971 972 973 974 975

Output:

1
```

利用二叉查找树的中序遍历为有序的性质,计算中序遍历中临近的两个节点之差的绝对值,取最小值。

```java
C
CyC2018 已提交
976 977
private int minDiff = Integer.MAX_VALUE;
private TreeNode preNode = null;
C
CyC2018 已提交
978

C
CyC2018 已提交
979 980 981
public int getMinimumDifference(TreeNode root) {
    inOrder(root);
    return minDiff;
C
CyC2018 已提交
982 983
}

C
CyC2018 已提交
984 985 986 987 988 989
private void inOrder(TreeNode node) {
    if (node == null) return;
    inOrder(node.left);
    if (preNode != null) minDiff = Math.min(minDiff, node.val - preNode.val);
    preNode = node;
    inOrder(node.right);
C
CyC2018 已提交
990 991 992
}
```

C
CyC2018 已提交
993
## 10. 寻找二叉查找树中出现次数最多的值
C
CyC2018 已提交
994

C
CyC2018 已提交
995 996 997
501\. Find Mode in Binary Search Tree (Easy)

[Leetcode](https://leetcode.com/problems/find-mode-in-binary-search-tree/description/) / [力扣](https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/description/)
C
CyC2018 已提交
998 999

```html
C
CyC2018 已提交
1000 1001 1002 1003 1004
   1
    \
     2
    /
   2
C
CyC2018 已提交
1005

C
CyC2018 已提交
1006
return [2].
C
CyC2018 已提交
1007 1008 1009 1010 1011
```

答案可能不止一个,也就是有多个值出现的次数一样多。

```java
C
CyC2018 已提交
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
private int curCnt = 1;
private int maxCnt = 1;
private TreeNode preNode = null;

public int[] findMode(TreeNode root) {
    List<Integer> maxCntNums = new ArrayList<>();
    inOrder(root, maxCntNums);
    int[] ret = new int[maxCntNums.size()];
    int idx = 0;
    for (int num : maxCntNums) {
        ret[idx++] = num;
    }
    return ret;
C
CyC2018 已提交
1025 1026
}

C
CyC2018 已提交
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
private void inOrder(TreeNode node, List<Integer> nums) {
    if (node == null) return;
    inOrder(node.left, nums);
    if (preNode != null) {
        if (preNode.val == node.val) curCnt++;
        else curCnt = 1;
    }
    if (curCnt > maxCnt) {
        maxCnt = curCnt;
        nums.clear();
        nums.add(node.val);
    } else if (curCnt == maxCnt) {
        nums.add(node.val);
    }
    preNode = node;
    inOrder(node.right, nums);
C
CyC2018 已提交
1043 1044 1045
}
```

C
CyC2018 已提交
1046
# Trie
C
CyC2018 已提交
1047

C
CyC2018 已提交
1048
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
C
CyC2018 已提交
1049 1050 1051

Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。

C
CyC2018 已提交
1052
## 1. 实现一个 Trie
C
CyC2018 已提交
1053

C
CyC2018 已提交
1054 1055 1056
208\. Implement Trie (Prefix Tree) (Medium)

[Leetcode](https://leetcode.com/problems/implement-trie-prefix-tree/description/) / [力扣](https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/)
C
CyC2018 已提交
1057 1058

```java
C
CyC2018 已提交
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
class Trie {

    private class Node {
        Node[] childs = new Node[26];
        boolean isLeaf;
    }

    private Node root = new Node();

    public Trie() {
    }

    public void insert(String word) {
        insert(word, root);
    }

    private void insert(String word, Node node) {
        if (node == null) return;
        if (word.length() == 0) {
            node.isLeaf = true;
            return;
        }
        int index = indexForChar(word.charAt(0));
        if (node.childs[index] == null) {
            node.childs[index] = new Node();
        }
        insert(word.substring(1), node.childs[index]);
    }

    public boolean search(String word) {
        return search(word, root);
    }

    private boolean search(String word, Node node) {
        if (node == null) return false;
        if (word.length() == 0) return node.isLeaf;
        int index = indexForChar(word.charAt(0));
        return search(word.substring(1), node.childs[index]);
    }

    public boolean startsWith(String prefix) {
        return startWith(prefix, root);
    }

    private boolean startWith(String prefix, Node node) {
        if (node == null) return false;
        if (prefix.length() == 0) return true;
        int index = indexForChar(prefix.charAt(0));
        return startWith(prefix.substring(1), node.childs[index]);
    }

    private int indexForChar(char c) {
        return c - 'a';
    }
C
CyC2018 已提交
1113 1114 1115
}
```

C
CyC2018 已提交
1116
## 2. 实现一个 Trie,用来求前缀和
C
CyC2018 已提交
1117

C
CyC2018 已提交
1118 1119 1120
677\. Map Sum Pairs (Medium)

[Leetcode](https://leetcode.com/problems/map-sum-pairs/description/) / [力扣](https://leetcode-cn.com/problems/map-sum-pairs/description/)
C
CyC2018 已提交
1121 1122

```html
C
CyC2018 已提交
1123 1124 1125 1126
Input: insert("apple", 3), Output: Null
Input: sum("ap"), Output: 3
Input: insert("app", 2), Output: Null
Input: sum("ap"), Output: 5
C
CyC2018 已提交
1127 1128 1129
```

```java
C
CyC2018 已提交
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
class MapSum {

    private class Node {
        Node[] child = new Node[26];
        int value;
    }

    private Node root = new Node();

    public MapSum() {

    }

    public void insert(String key, int val) {
        insert(key, root, val);
    }

    private void insert(String key, Node node, int val) {
        if (node == null) return;
        if (key.length() == 0) {
            node.value = val;
            return;
        }
        int index = indexForChar(key.charAt(0));
        if (node.child[index] == null) {
            node.child[index] = new Node();
        }
        insert(key.substring(1), node.child[index], val);
    }

    public int sum(String prefix) {
        return sum(prefix, root);
    }

    private int sum(String prefix, Node node) {
        if (node == null) return 0;
        if (prefix.length() != 0) {
            int index = indexForChar(prefix.charAt(0));
            return sum(prefix.substring(1), node.child[index]);
        }
        int sum = node.value;
        for (Node child : node.child) {
            sum += sum(prefix, child);
        }
        return sum;
    }

    private int indexForChar(char c) {
        return c - 'a';
    }
C
CyC2018 已提交
1180 1181 1182
}
```

C
CyC2018 已提交
1183 1184 1185 1186 1187 1188






C
CyC2018 已提交
1189
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-2.png"></img></div>