递归遍历
前序遍历
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function preTraversal(root: TreeNode | null, result: number[]){
if(!root) return;
result.push(root.val);
preTraversal(root.left, result);
preTraversal(root.right, result);
}
function preorderTraversal(root: TreeNode | null): number[] {
let result = [];
preTraversal(root, result);
return result;
};
中序遍历
function traversal(root: TreeNode | null, results: number[]){
if(!root) return;
traversal(root.left, results);
results.push(root.val);
traversal(root.right, results);
}
function inorderTraversal(root: TreeNode | null): number[] {
let results = [];
traversal(root, results)
return results;
};
后序遍历
function traversal(root: TreeNode | null, results: number[]){
if(!root) return;
traversal(root.left, results);
traversal(root.right, results);
results.push(root.val);
}
function postorderTraversal(root: TreeNode | null): number[] {
let results = [];
traversal(root, results)
return results;
};
迭代遍历 (需要回看)
前序遍历
前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。
为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。
function preorderTraversal(root: TreeNode | null): number[] {
if(!root) return [];
let results = [];
let helperStact = [root];
while(helperStact.length > 0){
let node = helperStact.pop();
results.push(node.val);
node.right && helperStact.push(node.right);
node.left && helperStact.push(node.left);
}
return results;
};
中序遍历
分析一下为什么刚刚写的前序遍历的代码,不能和中序遍历通用呢,因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。
那么再看看中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
function inorderTraversal(root: TreeNode | null): number[] {
if (!root) return [];
let results = [];
let helperStact = [];
let point = root;
while (point || helperStact.length > 0) {
if (point) {
helperStact.push(point);
point = point.left;
} else {
let node = helperStact.pop();
results.push(node.val);
point = node.right;
}
}
return results;
};
后序遍历
先序遍历是中左右,后序遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。
function postorderTraversal(root: TreeNode | null): number[] {
let results = [];
let helperStack = [root];
while(helperStack.length > 0){
let node = helperStack.pop();
node && results.push(node.val);
node?.left && helperStack.push(node.left);
node?.right && helperStack.push(node.right);
}
return results.reverse();
};
层序遍历
102.二叉树的层序遍历
迭代法
function levelOrder(root: TreeNode | null): number[][] {
if (!root) return [];
let thisLevelQueue = [root];
let nextLevelQueue = [];
let results: number[][] = [];
let levelResult: number[] = [];
while (nextLevelQueue.length > 0 || thisLevelQueue.length > 0) {
while (thisLevelQueue.length > 0) {
let node = thisLevelQueue.shift();
node && levelResult.push(node.val);
node?.left && nextLevelQueue.push(node.left);
node?.right && nextLevelQueue.push(node.right);
}
results.push(levelResult);
thisLevelQueue = nextLevelQueue;
levelResult = [];
nextLevelQueue = [];
}
return results;
};
官方解法:只用了一个队列
function levelOrder(root: TreeNode | null): number[][] {
let helperQueue: TreeNode[] = [];
let res: number[][] = [];
let tempArr: number[] = [];
if (root !== null) helperQueue.push(root);
let curNode: TreeNode;
while (helperQueue.length > 0) {
for (let i = 0, length = helperQueue.length; i < length; i++) {
curNode = helperQueue.shift()!;
tempArr.push(curNode.val);
if (curNode.left !== null) {
helperQueue.push(curNode.left);
}
if (curNode.right !== null) {
helperQueue.push(curNode.right);
}
}
res.push(tempArr);
tempArr = [];
}
return res;
};
递归法
function levelOrder(root: TreeNode | null): number[][] {
let results: number[][] = []
function traverse(root, level){
if(!root) return;
if(results.length === level){
results.push([]);
}
results[level].push(root.val);
traverse(root.left, level + 1);
traverse(root.right, level + 1);
}
traverse(root, 0);
return results;
};
107.二叉树的层序遍历 ||
function levelOrderBottom(root: TreeNode | null): number[][] {
if(!root) return [];
let helperQueue = [root];
let results = [];
while(helperQueue.length > 0){
let levelResult = [];
let levelLength = helperQueue.length;
for(let i = 0; i < levelLength; i++){
let node = helperQueue.shift();
levelResult.push(node.val);
node.left && helperQueue.push(node.left);
node.right && helperQueue.push(node.right);
}
results.unshift(levelResult);
levelResult = [];
}
return results;
};
199.二叉树的右视图
function rightSideView(root: TreeNode | null): number[] {
if(!root) return [];
let results = [];
let helperQueue = [root];
while(helperQueue.length > 0){
let len = helperQueue.length;
for(let i = 0; i < len; i++){
let node = helperQueue.shift();
if(i === len - 1){
results.push(node.val);
}
node.left && helperQueue.push(node.left);
node.right && helperQueue.push(node.right);
}
}
return results;
};
637.二叉树的层平均值
function averageOfLevels(root: TreeNode | null): number[] {
if(!root) return [];
let helperQueue = [root];
let results = [];
while(helperQueue.length > 0){
let len = helperQueue.length;
let levelSum = 0;
for(let i = 0; i < len; i++){
let node = helperQueue.shift();
levelSum += node.val;
node.left && helperQueue.push(node.left);
node.right && helperQueue.push(node.right);
}
results.push(levelSum / len);
}
return results;
};
429.N叉树的层序遍历
function levelOrder(root: _Node | null): number[][] {
if (!root) return [];
let helperQueue = [root];
let results = [];
while (helperQueue.length > 0) {
let len = helperQueue.length;
let levelResult = [];
for (let i = 0; i < len; i++) {
let node = helperQueue.shift();
levelResult.push(node.val)
for (let child of node.children) {
child && helperQueue.push(child);
}
}
results.push(levelResult);
}
return results;
};
可以优化:
for (let child of node.children) {
child && helperQueue.push(child);
}
改为:
helperQueue.push(...node.children);
515.在每个树行中找最大值
function largestValues(root: TreeNode | null): number[] {
if(!root) return [];
let helperQueue = [root];
let results = [];
while(helperQueue.length > 0){
let len = helperQueue.length;
let max: number;
for(let i = 0; i < len; i++){
let node = helperQueue.shift();
console.log(max, node.val, Math.max(max, node.val))
max = max !== undefined ? Math.max(max, node.val) : node.val;
node.left && helperQueue.push(node.left);
node.right && helperQueue.push(node.right);
}
console.log(max);
results.push(max);
}
return results;
};
116.填充每个节点的下一个右侧节点指针
function connect(root: _Node | null): _Node | null {
if(!root) return null;
let helperQueue = [root];
while(helperQueue.length > 0){
let len = helperQueue.length;
let preNode: _Node, curNode: _Node;
for(let i = 0; i < len; i++){
if(i === 0){
preNode = helperQueue.shift();
} else{
curNode = helperQueue.shift();
console.log(curNode.val, preNode.val);
preNode.next = curNode;
preNode = curNode;
}
preNode.left && helperQueue.push(preNode.left);
preNode.right && helperQueue.push(preNode.right);
}
}
return root;
};
117.填充每个节点的下一个右侧节点指针II
function connect(root: _Node | null): _Node | null {
if(!root) return null;
let helperQueue = [root];
while(helperQueue.length > 0){
let len = helperQueue.length;
let preNode: _Node, curNode: _Node;
for(let i = 0; i < len; i++){
if(i === 0){
preNode = helperQueue.shift();
} else{
curNode = helperQueue.shift();
console.log(curNode.val, preNode.val);
preNode.next = curNode;
preNode = curNode;
}
preNode.left && helperQueue.push(preNode.left);
preNode.right && helperQueue.push(preNode.right);
}
}
return root;
};
104.二叉树的最大深度
function maxDepth(root: TreeNode | null): number {
let maxLevel = 0;
function traverse(root, level){
if(maxLevel < level) maxLevel = level;
if(!root) return level;
traverse(root.left, level + 1);
traverse(root.right, level + 1);
}
traverse(root, 0);
return maxLevel;
};
111.二叉树的最小深度
function minDepth(root: TreeNode | null): number {
if(!root) return 0;
let helperQueue = [root];
let level = 0;
while(helperQueue.length > 0){
let len = helperQueue.length;
level++;
for(let i = 0; i< len; i++){
let node = helperQueue.shift();
if(!node.left && !node.right) return level;
node.left && helperQueue.push(node.left);
node.right && helperQueue.push(node.right);
}
}
return level;
};