105. 从前序与中序遍历序列构造二叉树

10 篇文章 0 订阅

如题,根据前序与中序遍历序列构造二叉树

整体思路:
① 前序遍历的第一个元素,必然是二叉树的根节点
② 在中序遍历中找到前序遍历第一个元素的位置
③ 该位置左边的所有点都是二叉树的左子树元素,该位置右边的所有点都是二叉树的右子树元素

思路一:递归+字典
由整体思路可以构建子函数用于递归,不断求子树的左右子树,直到叶子节点。
代码如下:

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

from typing import List

class Solution:

	def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
		inorder_dic = {val: i for i, val in enumerate(inorder)}   #求每个字母在中序遍历中的位置
		print(inorder_dic)
		
		# 递归求解子树的左右子树,直到叶子节点
		# pre1, pre2, in1, in2 分别表示子树在前序遍历和中序遍历序列的开始位置和结束位置
		def buildSubTree(pre1, pre2, in1, in2, inorder_dic):
			# 子序列只有一个元素,说明是叶子节点了,返回该节点
			if pre1 == pre2:
				return TreeNode(preorder[pre1])
			
			if pre1 > pre2:
				return None
				
			# 前序遍历子序列的第一个元素,表示该子树的根节点,用top存放
			top = preorder[pre1]
			# 构建子树
			tree = TreeNode(top)
			# 获得该子树的根节点在中序遍历序列的位置
			location = inorder_dic[top]
			
			# 求该子树的左子树
			# pre1 = pre+1; pre2 = pre1 + (location - in1); 
			# (location - in1)表示左子树的元素个数,子树根节点在中序遍历的位置减去中序遍历初始位置
			# in1 = in1; in2 = location -1
			tree.left = buildSubTree(pre1+1, pre1+(location-in1), in1, location-1, inorder_dic)
			
			# 求该子树的右子树
			# pre1 = pre1 + (location - in1) + 1;  pre2 = pre2; 
			# 前序遍历初始位置加上左子树元素数后及根节点+1,为右子树前序遍历初始位置
			# in1 = location + 1;  in2 = in2
			tree.right = buildSubTree(pre1+(location-in1)+1, pre2, location+1, in2, inorder_dic)
			return tree
			
		return buildSubTree(0, len(preorder) - 1, 0, len(inorder) - 1, inorder_dic)
		

if __name__ == "__main__":
	preorder = [3,9,20,15,7]
	inorder = [9,3,15,20,7]
	print(Solution.buildTree("", preorder, inorder))

思路二:栈+迭代+字典
【该思路来自LeetCode题解】
我们用一个栈保存已经遍历过的节点,遍历前序遍历的数组,一直作为当前根节点的左子树,直到当前节点和中序遍历的数组的节点相等了,那么我们正序遍历中序遍历的数组,倒着遍历已经遍历过的根节点(用栈的 pop 实现),找到最后一次相等的位置,把它作为该节点的右子树。
作者:windliang
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by–22/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

代码如下:
public TreeNode buildTree(int[] preorder, int[] inorder) {
    if (preorder.length == 0) {
        return null;
    }
    Stack<TreeNode> roots = new Stack<TreeNode>();
    int pre = 0;
    int in = 0;
    //先序遍历第一个值作为根节点
    TreeNode curRoot = new TreeNode(preorder[pre]);
    TreeNode root = curRoot;
    roots.push(curRoot);
    pre++;
    //遍历前序遍历的数组
    while (pre < preorder.length) {
        //出现了当前节点的值和中序遍历数组的值相等,寻找是谁的右子树
        if (curRoot.val == inorder[in]) {
            //每次进行出栈,实现倒着遍历
            while (!roots.isEmpty() && roots.peek().val == inorder[in]) {
                curRoot = roots.peek();
                roots.pop();
                in++;
            }
            //设为当前的右孩子
            curRoot.right = new TreeNode(preorder[pre]);
            //更新 curRoot
            curRoot = curRoot.right;
            roots.push(curRoot);
            pre++;
        } else {
            //否则的话就一直作为左子树
            curRoot.left = new TreeNode(preorder[pre]);
            curRoot = curRoot.left;
            roots.push(curRoot);
            pre++;
        }
    }
    return root;
}

作者:windliang
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--22/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值