leetcode-二叉树-【前中后序、层序、遍历、递归、后序处理子树问题】-【从前中后序构造二叉树】

2022年10月23日 10点57分

快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历

二叉树这种结构无非就是二叉链表,由于没办法简单改写成迭代形式,所以一般说二叉树的遍历框架都是指递归的形式

二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作。

二叉树题目的递归解法可以分两类思路,第一类是遍历一遍二叉树得出答案,第二类是通过分解问题计算出答案,这两类思路分别对应着 回溯算法核心框架 和 动态规划核心框架。

前中后序

void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 前序位置
    traverse(root.left);
    // 中序位置
    traverse(root.right);
    // 后序位置
}

前中后序的区别

中序位置主要用在 BST 场景中,你完全可以把 BST 的中序遍历认为是遍历有序数组

前序位置的代码只能从函数参数中获取父节点传递来的数据,而后序位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据。

一旦你发现题目和子树有关,那大概率要给函数设置合理的定义和返回值,在后序位置写代码了。

二叉树的最大深度

遍历解法

// 记录最大深度
int res = 0;
// 记录遍历到的节点的深度
int depth = 0;

// 主函数
int maxDepth(TreeNode root) {
	traverse(root);
	return res;
}

// 二叉树遍历框架
void traverse(TreeNode root) {
	if (root == null) {
		return;
	}
	// 前序位置
	depth++;
    if (root.left == null && root.right == null) {
        // 到达叶子节点,更新最大深度
		res = Math.max(res, depth);
    }
	traverse(root.left);
	traverse(root.right);
	// 后序位置
	depth--;
}

分解解法

// 一棵二叉树的最大深度可以通过子树的最大深度推导出来,这就是分解问题计算答案的思路
// 定义:输入根节点,返回这棵二叉树的最大深度
int maxDepth(TreeNode root) {
	if (root == null) {
		return 0;
	}
	// 利用定义,计算左右子树的最大深度
	int leftMax = maxDepth(root.left);
	int rightMax = maxDepth(root.right);
	// 整棵树的最大深度等于左右子树的最大深度取最大值,
    // 然后再加上根节点自己
	int res = Math.max(leftMax, rightMax) + 1;

	return res;
}

层序遍历

二叉树题型主要是用来培养递归思维的,而层序遍历属于迭代遍历

BFS 算法框架 就是从二叉树的层序遍历扩展出来的,常用于求无权图的最短路径问题

有些很明显需要用层序遍历技巧的二叉树的题目,也可以用递归遍历的方式去解决,而且技巧性会更强

// 输入一棵二叉树的根节点,层序遍历这棵二叉树
void levelTraverse(TreeNode root) {
    if (root == null) return;
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);

    // 从上到下遍历二叉树的每一层
    while (!q.isEmpty()) {
        int sz = q.size();
        // 从左到右遍历每一层的每个节点
        for (int i = 0; i < sz; i++) {
            TreeNode cur = q.poll();
            // 将下一层节点放入队列
            if (cur.left != null) {
                q.offer(cur.left);
            }
            if (cur.right != null) {
                q.offer(cur.right);
            }
        }
    }
}

前序遍历

226. 翻转二叉树

  • 遍历解法
    在这里插入图片描述
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        self.traverse(root)
        return root
    
    def traverse(self, root: Optional[TreeNode]):
        if not root:
            return
        
        temp = root.left
        root.left = root.right
        root.right = temp

        self.traverse(root.left)
        self.traverse(root.right)
  • 「分解问题」解法-递归
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return root
        left = self.invertTree(root.left)
        right = self.invertTree(root.right)
        root.left = right
        root.right = left
        return root

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

  • 三叉树解法【遍历】
class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:return root
    
        def traverse(node1:'Optional[Node]',node2:'Optional[Node]'):
            if not node1 or not node2:
                return
            # 将传入的两个节点穿起来
            node1.next = node2
            # 连接相同父节点的两个子节点
            traverse(node1.left,node1.right)
            traverse(node2.left,node2.right)
            # 连接跨越父节点的两个子节点
            traverse(node1.right,node2.left)
            
        traverse(root.left,root.right)
        return root

114. 二叉树展开为链表

递归解法

class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:return 
        self.flatten(root.left)
        self.flatten(root.right)
        left = root.left
        right = root.right
        root.left = None
        root.right = left
        p = root
        while p.right:
            p = p.right
        p.right = right

构造二叉树

    1. 从前序与中序遍历序列构造二叉树
    1. 从中序与后序遍历序列构造二叉树
    1. 根据前序和后序遍历构造二叉树
    1. 最大二叉树

2022年10月25日 09点09分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值