LeetCode114 二叉树展开为链表
题目
解题
解题一:前序遍历(递归 + 栈)
递归版本:
// javascript
var flatten = function(root) {
const list = [];
const preorderTraversal = (root) => {
if (root === null) return;
list.push(root);
preorderTraversal(root.left);
preorderTraversal(root.right);
};
preorderTraversal(root);
for (let i = 0; i < list.length - 1; i++) {
list[i].left = null;
list[i].right = list[i + 1];
}
};
迭代版本:
// javascript
var flatten = function(root) {
const list = new Array(), stk = new Array();
while (root !== null || stk.length > 0) {
while (root !== null) {
list.push(root);
stk.push(root);
root = root.left;
}
root = stk.pop();
root = root.right;
}
for (let i = 0; i < list.length - 1; ++i) {
list[i].left = null;
list[i].right = list[i + 1];
}
};
解题二:前序遍历和展开同步进行
递归版本:
注意当前写法的 dfs 里面要记录右子树 B 的根节点,左子树的根节点 A 可以不记录。因为左子树的根节点 A 是当前根节点 C 的后继节点,当调用 visit 处理该左子树的根节点 A 时,会把 C 的 left 指向 null(不影响,因为已经在处理左子树),C 的 right 指向 A(完蛋了原本的 right 被覆盖掉)。等回到 C 的那层递归时,原本的右子树找不着惹!
// javascript
var flatten = function(root) {
const visit = (cur) => {
// tail = null 代表是第一个加入的节点,所以无前驱节点
if (tail !== null) {
// 将前一个节点的左指针置为 null,右指针置为 cur
tail.left = null;
tail.right = cur;
}
tail = cur;
};
const dfs = (root) => {
if (root === null) return;
// 要保存右指针,左指针可以不存
const left = root.left, right = root.right;
visit(root);
dfs(left);
dfs(right);
};
let tail = null;
dfs(root);
};
// javascript
var flatten = function(root) {
if (root === null) return;
const stk = [root];
let prev = null;
while (stk.length > 0) {
const curr = stk.pop();
if (prev !== null) {
prev.left = null;
prev.right = curr;
}
prev = curr;
// 先 right 后 left
if (curr.right !== null) stk.push(curr.right);
if (curr.left !== null) stk.push(curr.left);
}
};
解题三:寻找前驱节点
这段代码真的是绝,不走一遍很容易 Lost 丫!
// javascript
var flatten = function(root) {
while (root !== null) {
if (root.left !== null) {
let predesessor = root.left;
while (predesessor.right !== null) {
predesessor = predesessor.right;
}
predesessor.right = root.right;
// 注意顺序
root.right = root.left;
root.left = null;
}
// 都是 root = root.right
// 因为如果有左子树,会让左子树最右的节点的 right 指向 root 的右子树根节点
// 如果左子树是叶子节点,那么就是左子树的 right 指向 root 的右子树根节点
// 然后 root 的右指针指向了左子树
// 于是乎原先的左子树现在被 root 的右指针指着啦!
root = root.right;
}
};