二叉树:二叉树层序遍历、102.二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

提示:努力生活,开心、快乐的一天


二叉树层序遍历

思路

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树,
需要借用一个辅助数据结构即队列来实现队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑

102.二叉树的层序遍历

题目链接:102.二叉树的层序遍历

💡解题思路

  1. 定义一个数组(二维数组),返回最终结果;定义一个队列,并将root头结点加入队列中
  2. 二叉树非空判断
  3. 开始循环,循环的条件是队列中不为空;获取队列的长度,也就是每层的结点数;定义一个数组,存放每一层的结点
  4. 根据结点数进行遍历,将队列的头部元素弹出,并加入到数组中,判断弹出的元素的左右结点是否存在,存在的话加入到队列中
  5. 每次循环将每层的数组加入到最终的返回结果中

🤔遇到的问题

  1. 队列不为空的判断,不能使用!queue,使用queue.length!==0
  2. 二叉树不为空,判断的应该是!root,而不是!stack

💻代码实现

var levelOrder = function (root) {
    //二维数组
    let res = []
    //队列
    let queue = []
    //加入头节点
    queue.push(root)
    //二叉树不为空的判断
    if (!root) return res
    //队列为空,结束循环
    while (queue.length!==0) {
        //每层的节点数
        let len = queue.length
        //每层的节点数组
        let cur = []
        //根据节点数进行遍历
        for (let i = 0; i < len; i++){
            //弹出队列
            let node = queue.shift()
            cur.push(node.val)
            // 存放当前层下一层的节点
            //左右结点存在,并加入队列中
            node.left && queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        //每层的数组加入到总的二维数组中
        res.push(cur)
    }
    return res
};

🎯题目总结

  1. 存放每一层的结点数
  2. 根据节点数进行遍历时,弹出相应数量的结点的同时,存放当前层下一层的节点

226.翻转二叉树

题目链接:226.翻转二叉树

💡解题思路

  1. 只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果
  2. 递归遍历:遵循递归三部曲
  • 确定递归函数的参数和返回值:参数就是要传入节点的指针,不需要其他参数了
  • 确定终止条件:当前节点为空的时候,就返回
  • 确定单层递归的逻辑:因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树
  1. 层序遍历:在向栈中添加左右结点之前,先将左右结点进行交换

🤔遇到的问题

  1. 交换左右结点出错

💻代码实现

递归遍历(前序遍历)

var invertTree = function(root) {
    //终止条件
    if(!root) return null
    //交换左右节点
    let leftNode = root.left
    root.left = invertTree(root.right)
    root.right = invertTree(leftNode)
    return root
};

层序遍历

var invertTree = function (root) {
    const invertNode = (root, left, right) => {
        let temp = left;
        left = right
        right = temp
        root.left = left
        root.right = right
    }
    if (!root) return root
    let queue = []
    queue.push(root)
    while (queue.length) {
        let len = queue.length
        for (let i = 0; i < len; i++) {
            let node = queue.shift()
            invertNode(node, node.left, node.right)
            node.left && queue.push(node.left)
            node.right && queue.push(node.right)
        }
    }
    return root
};

🎯题目总结

层序遍历的交换左右结点需要注意


101. 对称二叉树

题目链接:101. 对称二叉树

💡解题思路

  1. 二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树,如何进行比较?比较的是两个子树的里侧和外侧的元素是否相等
    在这里插入图片描述
  2. “后序遍历”:遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中
  3. 递归法(后序遍历):递归三部曲
    - 确定递归函数的参数和返回值:因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点
    - 确定终止条件左节点为空,右节点不为空,不对称,return false;左不为空,右为空,不对称 return false;左右都为空,对称,返回true;左右都不为空,比较节点数值,不相同就return false
    - 确定单层递归的逻辑:此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。1、比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子;2、比较内侧是否对称,传入左节点的右孩子,右节点的左孩子;3、如果左右都对称就返回true ,有一侧不对称就返回false
  4. 迭代法:使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历)
    迭代法,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的

🤔遇到的问题

  1. 递归遍历:终止条件判断是否为null不能用!leftNode
  2. 迭代法:两个结点一起比较,同时存,同时取

💻代码实现

递归遍历(后序遍历)

var isSymmetric = function (root) {
  // 使用递归遍历左右子树 递归三部曲
    // 1. 确定递归的参数 root.left root.right和返回值true false 
	const compare = (left, right) => {
		// 2. 确定终止条件 空的情况
		if (left === null && right !== null) return false
		else if (left !== null && right === null) return false
		else if (left === null && right === null) return true
		else if (left.val !== right.val) return false
		// 3. 确定单层递归逻辑
		let outSide = compare(left.left, right.right)
		let inSide = compare(left.right, right.left)
		return outSide && inSide
	}
	if (!root) return true
	return compare(root.left, root.right)
}

迭代法

// 迭代方法判断是否是对称二叉树
  // 首先判断root是否为空
var isSymmetric = function (root) {
	if (!root) return true
	let queue = []
  //把左右两个子树要比较的元素顺序放进队列中,然后成对成对的取出来进行比较
	queue.push(root.left)
	queue.push(root.right)
	while (queue.length) {
		let leftNode = queue.shift()
		let rightNode = queue.shift()
		if (leftNode === null && rightNode === null) {
			continue
		}
    //终止条件
		if (leftNode === null || rightNode === null || leftNode.val !== rightNode.val) {
			return false
		}
    //左节点左孩子入队
    //右节点右孩子入队
    //这两个属于外侧节点相互比较
		queue.push(leftNode.left)
		queue.push(rightNode.right)
    //左节点右孩子入队
    //右节点左孩子入队
    //这两个属于内侧节点相互比较
		queue.push(leftNode.right)
		queue.push(rightNode.left)
	}
	return true
}

🎯题目总结

递归法和迭代法,递归依然通过递归三部曲来解决了这道题目
迭代法中使用了队列,需要注意的是这不是层序遍历,而且仅仅通过一个容器来成对的存放我们要比较的元素,知道这一本质之后就发现,用队列,用栈,甚至用数组,都是可以的

🎈今日心得

使用递归解题,一定了解采用的是递归中的那种遍历方式;另外迭代法还需要继续加强

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值