Day13: 二叉树基础 |

递归遍历

前序遍历

/**
 * 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;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值