代码随想录算法训练营第十五天|层序遍历 10、226.翻转二叉树、101.对称二叉树 2「二叉树」

140 阅读4分钟

102. 二叉树的层序遍历

题目

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

思路

利用队列,设置两层循环,第一层循环判断条件为队列是否为空,然后在循环内部用一个变量size获取队列长度,声明一个数组,存储当前层数的元素,设置第二层循环判断条件是当前队列长度,每次判断结束size--,在循环内部获取队列的头部节点,推入数组中,然后判断分别当前节点是否有左右节点,如果有推入队列中,最后把当前数组推入结果数组中,最后在循环外输出结果数组。

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        const arr = []
        while (size--) {
            let node = queue.shift()
            arr.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        res.push(arr)
    }
    return res
};

总结:

做完了二叉树的前中后序遍历后后,再来看层序遍历,感觉简单了很多。

107. 二叉树的层序遍历 II

题目

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

思路

和102层序遍历一样,最后输出的时候把结果数组逆序

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrderBottom = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        const arr = []
        while (size--) {
            let node = queue.shift()
            arr.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        res.push(arr)
    }
    return res.reverse()
};

199. 二叉树的右视图

题目

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路

在将每层元素推入当前层数数组的时候,判断当前size是否为0,即判断当前元素是否为该层的最后一个元素,如果是,那就推入当前层数数组。

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var rightSideView = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        while (size--) {
            let node = queue.shift()
            size===0&&res.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
    }
    return res
};

总结:

一开始想只在队列中存入右节点,后来变成先判断是否有右节点,如果没有就存入左节点,结果发现不能判断下一层的左节点,总之说来说去逻辑就只有一句话,就是判断当前元素是否为最右边的节点。

637. 二叉树的层平均值

题目

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

思路

很简单,把每层数组替换成当前数组内元素总和除以元素个数,即求当前层的平均值,然后再推入结果数组中输出。

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var averageOfLevels = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        const arr = [],device = size
        while (size--) {
            let node = queue.shift()
            arr.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        let sum = arr.reduce((sum,num)=>sum+num,0)
        // console.log(sum/size)
        res.push(parseFloat(sum/device))
    }
    return res
};

429. N 叉树的层序遍历

题目

给定一个 N 叉树,返回其节点值的_层序遍历_。(即从左到右,逐层遍历)。 树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

思路

在遍历每层元素的时候额外添加一个for循环,把children里的每个子元素单独添加到队列中。

代码

/**
 * // Definition for a Node.
 * function Node(val,children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */

/**
 * @param {Node|null} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        const arr = []
        while (size--) {
            let node = queue.shift()
            arr.push(node.val)
            for (let i = 0; i< node.children.length;i++) {
                node.children[i]&&queue.push(node.children[i])
            }
        }
        res.push(arr)
    }
    return res
};

515. 在每个树行中找最大值

题目

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

思路

把每层数组替换成每层数组中的最大值然后推入结果数组最后输出。

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var largestValues = function(root) {
    const queue = [],res = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        const arr = []
        while (size--) {
            let node = queue.shift()
            arr.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        res.push(Math.max(...arr))
    }
    return res
};

116. 填充每个节点的下一个右侧节点指针

题目

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。 初始状态下,所有 next 指针都被设置为 NULL

思路

利用层序遍历,判断如果当前元素指向不是最后一个元素,就把这个元素的next指针指向下一个元素,也就是队列的队头元素。

代码

/**
 * // Definition for a Node.
 * function Node(val, left, right, next) {
 *    this.val = val === undefined ? null : val;
 *    this.left = left === undefined ? null : left;
 *    this.right = right === undefined ? null : right;
 *    this.next = next === undefined ? null : next;
 * };
 */

/**
 * @param {Node} root
 * @return {Node}
 */
var connect = function(root) {
    const queue = []
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        for (let i = 0;i<size;i++) {
            let node = queue.shift()
            if (i<size-1) {
                node.next = queue[0]
            }
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
    }
    return root
};

总结:

自己写的时候总是在想是不是要设置一个指针,去指向前一个元素,然后用前一个元素的next指向当前的元素,非常复杂,其实下一个元素就是当前队列的队头元素。

117. 填充每个节点的下一个右侧节点指针 II

题目

总结:

和上一题没区别

104. 二叉树的最大深度

题目

给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。

思路

把每层数组放入结果数组输出替换成一个计数器,然后输出计数器

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxDepth = function(root) {
    const queue = []
    let count =0
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        while (size--) {
            let node = queue.shift()
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        count++
    }
    return count
};

总结:

比较简单。

111. 二叉树的最小深度

题目

给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。

思路

判断如果一个节点没有左节点且没有右节点就直接返回深度,最后再输出一下深度以免该树只有一个分支

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var minDepth = function(root) {
    const queue = []
    let count =0
    root&&queue.push(root)
    while (queue.length) {
        let size = queue.length
        count++
        while (size--) {
            let node = queue.shift()
            if (!node.left&&!node.right) {
                return count
            }
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
    }
    return count
};

总结:

一开始写的时候把判断输出的顺序弄错了,弄到添加左右节点的后面,放在前面就没问题了。

226. 翻转二叉树

题目

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

思路

  1. 递归:
    1. 先设置参数和返回值分别是左右节点,最后返回根节点
    2. 先设置退出递归的条件,即当前节点为null
    3. 设置单层逻辑,调换左右节点位置,然后向下寻找节点
  2. 迭代:
    1. 利用栈每次取出栈顶元素,判断是否存在,存在就向下寻找节点,按先序放入栈中,不存在就取出上一个节点元素进行逻辑操作
  3. 层序遍历:
    1. 利用队列,每次取出队头元素进行逻辑操作,向下寻找节点,从队尾插入

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */

// 递归
var invertTree = function(root) {
    if (root === null) return root
    let node = root.right
    root.right = invertTree(root.left)
    root.left = invertTree(node)
    return root
};

// 统一迭代
var invertTree = function(root) {
    if (root === null) return root
    const stack = [root]
    while (stack.length) {
        let node = stack.pop()
        if (node) {
            if (node.right) stack.push(node.right)
            if (node.left) stack.push(node.left)
            stack.push(node)
            stack.push(null)
        }else {
            node = stack.pop()
            let nodeRight = node.right
            node.right = node.left
            node.left = nodeRight
        }
    }
    return root
};

// 层序遍历
var invertTree = function(root) {
    if (root === null) return root
    const queue = [root]
    while (queue.length) {
        let size = queue.length
        while(size--){
            const node = queue.shift()
            let tmp = node.right
            node.right = node.left
            node.left = tmp
            node.left && queue.push(node.left)
            node.right && queue.push(node.right)
        }
    }
    return root
};

总结:

逻辑不难,但是细节要琢磨清楚。

101. 对称二叉树

题目

给你一个二叉树的根节点 root , 检查它是否轴对称。

思路

  1. 递归:
    1. 设置传入参数和返回值,参数是左右节点,返回布尔值
    2. 设置退出递归条件,如果不对称返回false,对称返回true
    3. 设置单层逻辑,分别对对侧的节点进行比较,然后利用递归对子节点比较,返回布尔值
  2. 迭代队列:
    1. 把左右节点放入队列中,每次取出两个节点进行逻辑比较,进行返回,然后把对侧节点按照对应顺序放入队列中
  3. 迭代栈:
    1. 和队列逻辑相同

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */

// 递归
var isSymmetric = function(root) {
    if (!root) return true
    return compare(root.left,root.right)
};

const compare = (left,right) => {
    if (!left&&right) return false
    else if (left&&!right) return false
    else if (!left&&!right) return true
    else if (left.val!== right.val) return false

    let outside = compare(left.left,right.right)
    let inside = compare(left.right,right.left)
    let res = outside&&inside

    return res
}

// 迭代队列:

var isSymmetric = function(root) {
    if (!root) return true
    const queue = [root.left,root.right]
    while (queue.length) {
        const left = queue.shift(),right = queue.shift()
        if (!left&&!right){
            continue
        }

        if (!left||!right||left.val!==right.val){
            return false
        }
        queue.push(left.left)
        queue.push(right.right)
        queue.push(left.right)
        queue.push(right.left)
    }
    return true
};

// 迭代栈:

var isSymmetric = function(root) {
    if (!root) return true
    const stack = [root.left,root.right]
    while (stack.length) {
        const left = stack.pop(),right = stack.pop()
        if (!left&&!right){
            continue
        }

        if (!left||!right||left.val!==right.val){
            return false
        }
        stack.push(left.left)
        stack.push(right.right)
        stack.push(left.right)
        stack.push(right.left)
    }
    return true
};

总结:

不难,是对二叉树理解的巩固

Day15总结

今天的内容很多,实际上我是分两次写完的,27号在高铁写完了层序遍历的内容,去深圳以后找房子准备入职工作做了好几天,今天2号全部安顿下来,其实30号1号也有时间写题,但是一旦脱离了学习状态后,再找回这种状态是一件很痛苦的事,总是喜欢拖延,明天就要入职了,有点紧张,说实话落下的内容已经太多,想要一次性补完不太现实,打算以每天写两天的题目来追赶进度,10天应该能追上,加油。