Skip to content

Commit

Permalink
supplement
Browse files Browse the repository at this point in the history
  • Loading branch information
yk committed Feb 13, 2024
1 parent 4f8df0c commit 8a1fcdc
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 2 deletions.
161 changes: 160 additions & 1 deletion content/posts/2024/01/0115.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: '0115-二叉树'
date: 2024-01-15T21:01:56+08:00
lastmod:
lastmod: 2024-02-07 17:28:23
tags: []
series: []
categories: []
Expand Down Expand Up @@ -414,3 +414,162 @@ public boolean isFullTree(TreeNode root) {
```

> 注意,还是那句话,具体问题具体分析,这种技巧,并不适合每种二叉树的问题,比如,一颗树,让你求整个树的中位数,树形 DP 的方式就做不到,其实就是没有最优子结构。
---

## 练习题

### 最低公共祖先 lc.236, git merge 的原理

```js
var lowestCommonAncestor = function (root, p, q) {
let ans = null
const dfs = (node) => {
if (node == null) {
return false
}
const leftRes = dfs(node.left)
const rightRes = dfs(node.right)
// 更容易理解的做法,向左右子树要信息,定义 dfs 返回是否含有 p 或 q
if (
(leftRes && rightRes) ||
((node.val == p.val || node.val == q.val) && (leftRes || rightRes))
) {
ans = node
return
}
if (node.val == p.val || node.val == q.val || leftRes || rightRes) {
return true
}
return false
}
dfs(root)
return ans
}
```

```js
// 更加抽象的代码
var lowestCommonAncestor = function (root, p, q) {
// 定义 traverse 返回遇到 p 或 q 的节点
const traverse = (root) => {
if (!root) return root
if (root == p) return p
if (root == q) return q
const left = traverse(root.left)
const right = traverse(root.right)
if (left && right) return root
return left ? left : right
}
return traverse(root)
}
```

### 二叉树中序后继节点问题 lcr053、lc285(vip)

顾名思义,最简单的,根据题意中序遍历即可得到答案:

```js
var inorderSuccessor = function (root, p) {
const stack = []
let nextIsRes = false
while (stack.length || root) {
while (root) {
stack.push(root)
root = root.left
}
const node = stack.pop()
if (nextIsRes) return node
if (node == p) nextIsRes = true
if (node.right) root = node.right
}
return null
}
```

但是面试怎么可能这么简单呢,挑选候选人,当然需要更优解,因此需要探索到新的思路

1. 节点有右侧节点,那么根据中序规则,后继节点是 右侧节点的最左边的子节点
2. 节点无右侧节点,那么根据中序规则,后续节点是 父节点中第一个作为左子节点的节点

如过遇上了 BST,则往往有需要利用上 BST 的性质

```js
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @return {TreeNode}
*/
var inorderSuccessor = function (root, p) {
if (p.right) {
let p1 = p.right
while (p1 && p1.left) {
p1 = p1.left
}
return p1
}
let res = null
let p1 = root
while (p1) {
if (p1.val > p.val) {
res = p1
p1 = p1.left
} else {
p1 = p1.right
}
}
return res
}
```

姊妹题:每个节点有一个 parent 节点,怎么找后继节点,原理基本一样,不做过多介绍。

### 二叉树序列化和反序列化 lc.297

```js
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/

/**
* Encodes a tree to a single string.
* @param {TreeNode} root
* @return {string}
*/
var serialize = function (root) {
const traverse = (root) => {
if (!root) return '#_'
let res = root.val + '_'
res += traverse(root.left)
res += traverse(root.right)
return res
}
return traverse(root)
}

/**
* Decodes your encoded data to tree.
* @param {string} data
* @return {TreeNode}
*/
var deserialize = function (data) {
const arr = data.split('_')
const generateTree = (arr) => {
let root = arr.shift()
if (root == '#') return null
root = new TreeNode(Number(root))
root.left = generateTree(arr)
root.right = generateTree(arr)
return root
}
return generateTree(arr)
}
/**
* Your functions will be called as such:
* deserialize(serialize(root));
*/
```
2 changes: 1 addition & 1 deletion content/posts/algorithm/优先队列的实现.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ JavaScript 中没有内置优先队列这个数据结构,需要自己来实现
```JavaScript
class PriorityQueue {
constructor(data, cmp) {
// 使用堆顶守卫,更方便上浮时父节点的获取 p = i << 1, 子节点本身就比较好获取倒是无所谓
// 使用堆顶守卫,更方便上浮时父节点的获取 p = i >> 1, 子节点本身就比较好获取倒是无所谓
this.data = [null, ...data];
this.cmp = cmp;
for (let i = this.data.length >> 1; i > 0; --i) this.down(i); // 对除最后一层的子节点进行堆化初始化
Expand Down

0 comments on commit 8a1fcdc

Please sign in to comment.