《剑指offer》-数据结构篇-树

题目

  1. 重建二叉树

  2. 树的子结构

  3. 二叉树的镜像

  4. 从上往下打印二叉树(层序遍历)

  5. 把二叉树打印成多行

  6. 按之字形顺序打印二叉树

  7. 二叉搜索树的第k个结点(中序遍历)

  8. 二叉搜索树的后序遍历序列(后序遍历)

  9. 二叉树中和为某一值的路径

  10. 二叉树的深度

  11. 平衡二叉树

  12. 二叉树的下一个结点

  13. 对称的二叉树

  14. 序列化二叉树

代码实现

重建二叉树

题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路:前序遍历的第一个结点是根节点,据此和中序遍历序列可以找到根节点的左子树、右子树包含的结点,返回的结果是树的层序遍历的结果{1,2,3,4,5,6,7,8}。典型题目,注意迭代的pre和tin的取值范围。

python 复制代码
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre)==0:
            return None
        root=TreeNode(pre[0])
        TinIndex=tin.index(pre[0])
        root.left=self.reConstructBinaryTree(pre[1:TinIndex+1], tin[0:TinIndex])
        root.right=self.reConstructBinaryTree(pre[TinIndex+1:], tin[TinIndex+1:])
        return root

树的子结构

题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:依次判断A与B的left、right,判断pRoot2是否是pRoot1的子结构。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        #这里认为pRoot1和pRoot2都为空时,没法判断子结构结果,认为比较的结果是False
        #if not pRoot1 and not pRoot2:
        #    return True
        if not pRoot1 or not pRoot2:
            return False
        return self.is_subtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
     
    def is_subtree(self, A, B):
        if not B:
            return True
        if not A or A.val != B.val:
            return False
        return self.is_subtree(A.left,B.left) and self.is_subtree(A.right, B.right)

二叉树的镜像

题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。

思路:二叉树每一层的结点进行左右交换,看得到的二叉树的结点数值是否一致。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Mirror(self, root):
        # write code here
        if not root:
            return None   
        left, right = root.left, root.right
        root.left = right
        root.right = left
        self.Mirror(root.left)
        self.Mirror(root.right)
        return root

从上往下打印二叉树(层序遍历)

题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:从左至右添加每一层的结点。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表
    def PrintFromTopToBottom(self, root):
        # write code here
        ret = [] 
        if root == None:
            return ret
        bfs = [root]
        while(bfs):
            tbfs = []
            for node in bfs:
                ret.append(node.val)
                if node.left:
                    tbfs.append(node.left)
                if node.right:
                    tbfs.append(node.right)
            bfs = tbfs
        return ret

把二叉树打印成多行

题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

思路:注意和第13题的区别:这里是每一层输出一行(用列表表示)。因而,输出是一个嵌套列表。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        if not pRoot:
            return []
        nodeStack=[pRoot]
        result=[]
        while nodeStack:
            res = []
            nextStack=[]
            for i in nodeStack:
                res.append(i.val)
                if i.left:
                    nextStack.append(i.left)
                if i.right:
                    nextStack.append(i.right)
            nodeStack=nextStack
            result.append(res)
        return result

按之字形顺序打印二叉树

题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:和第5题类似,但是这里需要对列表中的元素的位置序号进行"奇偶判断"。注意:enumerate()结果的序号是从0开始的。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        if not pRoot:
            return []
        nodeStack=[pRoot]
        result=[]
        while nodeStack:
            res = []
            nextStack=[]
            for i in nodeStack:
                res.append(i.val)
                if i.left:
                    nextStack.append(i.left)
                if i.right:
                    nextStack.append(i.right)
            nodeStack=nextStack
            result.append(res)
        returnResult=[]
        #上述代码的运行结果是[[z1],[z2],...,[zn]],z1...zn表示对应的每一层的结点的值
        for i,v in enumerate(result):
            if i%2==0:
                returnResult.append(v)
            else:
                returnResult.append(v[::-1])
        return returnResult

二叉搜索树的第k个结点(中序遍历)

题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如,(5,3,7,2,4,6,8)中,按结点数值大小顺序第三小结点的值为4。

思路:利用中序遍历实现。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 中序遍历找到第k个结点的数值
    def KthNode(self, pRoot, k):
        # write code here
        if not pRoot: return None
        stack = []
        while pRoot or stack:
            while pRoot:
                stack.append(pRoot)
                pRoot = pRoot.left
            pRoot = stack.pop()
            k -= 1
            if k == 0:
                return pRoot
            pRoot = pRoot.right

二叉搜索树的后序遍历序列(后序遍历)

题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:根据二叉搜索树性质:结点值大于结点的左结点的数值,小于结点的右结点的数值来实现。

python 复制代码
# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if len(sequence)==0:
            return False
        root = sequence[-1]
 
        i = 0
        for node in sequence[:-1]:
            if node > root:
                break
            i += 1
 
        for node in sequence[i:-1]:
            if node < root:
                return False
        left = True
        if i > 1:
            left = self.VerifySquenceOfBST(sequence[:i])
 
        right = True
        #i < (len(sequence)-1)以确保是二叉搜索树
        if (i < (len(sequence)-1))and left:
            right = self.VerifySquenceOfBST(sequence[i:-1])
        return left and right

二叉树中和为某一值的路径

题目描述:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

思路:递归,依据终止条件左结点=右结点=None且对应的根节点值是之前路径的总和中差的最后一项值。在前序、中序和后序遍历中只有前序遍历是最先访问根节点的,而且题中说在返回的list中数组长度大的数组在前,所以应该采用前序遍历的方法。前序遍历先访问左子树时,在每一个节点的根节点按照从左至右的顺序进行访问。将设定的值expectNumber与所经过的路径中除去最后一个节点的值的和进行相减,然后将结果与遍历的最后一个节点的值进行对比,如果相等的话则说明这条路径是我们所想要的,然后记录下来,返回ret。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        ret = []
        def dfs(root,sum_,tmp):
            if root:
                if root.left==None and root.right == None:
                    if root.val == sum_:
                        tmp.append(root.val)
                        ret.append(tmp[:])
                else:
                    tmp.append(root.val)
                    dfs(root.left,sum_-root.val,tmp[:])
                    dfs(root.right,sum_-root.val,tmp[:])
        dfs(root,expectNumber,[])
        return ret

二叉树的深度

题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思路:递归,求得根节点的左子树和右子树的深度,最后再加1。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot == None:
            return 0
        if pRoot.left == None and pRoot.right==None:
            return 1
        return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

平衡二叉树

题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。

思路:平衡二叉树的定义:是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。根据定义来直接判断。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if pRoot == None:
            return True
        if abs(self.TreeDepth(pRoot.left)-self.TreeDepth(pRoot.right)) > 1:
            return False
        return self.IsBalanced_Solution(pRoot.left) 
and self.IsBalanced_Solution(pRoot.right)
       
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot == None:
            return 0
        nLeft = self.TreeDepth(pRoot.left)
        nRight = self.TreeDepth(pRoot.right)
        return max(nLeft+1,nRight+1)#(nLeft+1 if nLeft > nRight else nRight +1)

二叉树的下一个结点

题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思路:判断结点是左、右结点,然后按照中序遍历的先左结点,后父结点,最后右结点的顺序遍历下一个结点。

python 复制代码
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre)==0:
            return None
        root=TreeNode(pre[0])
        TinIndex=tin.index(pre[0])
        root.left=self.reConstructBinaryTree(pre[1:TinIndex+1], tin[0:TinIndex])
        root.right=self.reConstructBinaryTree(pre[TinIndex+1:], tin[TinIndex+1:])
        return root

对称的二叉树

题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

思路:递归判断。注意和第12题的区别,这里不是生成一个镜像的二叉树,而是判断已有的二叉树是否是对称的。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None        
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        def is_same(p1,p2):
            if not p1 and not p2:
                return True
            if (p1 and p2) and p1.val==p2.val:
                return is_same(p1.left,p2.right) and is_same(p1.right,p2.left)
            return False
        if not pRoot:
            return True
        if pRoot.left and not pRoot.right:
            return False
        if not pRoot.left and pRoot.right:
            return False
        return is_same(pRoot.left,pRoot.right)

序列化二叉树

题目描述:请实现两个函数,分别用来序列化和反序列化二叉树。二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以!表示一个结点值的结束(value!)。二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

思路:序列化的过程:按照层序遍历的方式查找空节点,然后由"#"进行替换。反序列化的过程:查找不是"#"的结点值,然后添加,否则是None。

python 复制代码
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.index = -1
 
    def Serialize(self, root):
        # write code here
        if root:
            return str(root.val) + ' ' +\
                self.Serialize(root.left) + \
                self.Serialize(root.right)
        else:
            return '# '
 
    def Deserialize(self, s):
        # write code here
        l = s.split()
        self.index += 1
        if self.index >= len(s): 
            return None
        
        if l[self.index] != '#':
            root = TreeNode(int(l[self.index]))
            root.left = self.Deserialize(s)
            root.right = self.Deserialize(s)
        else:
            return None
        return root

结尾

亲爱的读者朋友:感谢您在繁忙中驻足阅读本期内容!您的到来是对我们最大的支持❤️

正如古语所言:"当局者迷,旁观者清"。您独到的见解与客观评价,恰似一盏明灯💡,能帮助我们照亮内容盲区,让未来的创作更加贴近您的需求。

若此文给您带来启发或收获,不妨通过以下方式为彼此搭建一座桥梁: ✨ 点击右上角【点赞】图标,让好内容被更多人看见 ✨ 滑动屏幕【收藏】本篇,便于随时查阅回味 ✨ 在评论区留下您的真知灼见,让我们共同碰撞思维的火花

我始终秉持匠心精神,以键盘为犁铧深耕知识沃土💻,用每一次敲击传递专业价值,不断优化内容呈现形式,力求为您打造沉浸式的阅读盛宴📚。

有任何疑问或建议?评论区就是我们的连心桥!您的每一条留言我都将认真研读,并在24小时内回复解答📝。

愿我们携手同行,在知识的雨林中茁壮成长🌳,共享思想绽放的甘甜果实。下期相遇时,期待看到您智慧的评论与闪亮的点赞身影✨!

万分感谢🙏🙏您的点赞👍👍、收藏⭐🌟、评论💬🗯️、关注❤️💚~


自我介绍:一线互联网大厂资深算法研发(工作6年+),4年以上招聘面试官经验(一二面面试官,面试候选人400+),深谙岗位专业知识、技能雷达图,已累计辅导15+求职者顺利入职大中型互联网公司。熟练掌握大模型、NLP、搜索、推荐、数据挖掘算法和优化,提供面试辅导、专业知识入门到进阶辅导等定制化需求等服务,助力您顺利完成学习和求职之旅(有需要者可私信联系)

友友们,自己的知乎账号为**"快乐星球"**,定期更新技术文章,敬请关注!

相关推荐
Coovally AI模型快速验证41 分钟前
数据集分享 | 智慧农业实战数据集精选
人工智能·算法·目标检测·机器学习·计算机视觉·目标跟踪·无人机
墨尘游子1 小时前
目标导向的强化学习:问题定义与 HER 算法详解—强化学习(19)
人工智能·python·算法
恣艺1 小时前
LeetCode 854:相似度为 K 的字符串
android·算法·leetcode
予早1 小时前
《代码随想录》刷题记录
算法
满分观察网友z2 小时前
别总想着排序!我在数据看板中悟出的O(N)求第三大数神技(414. 第三大的数)
算法
满分观察网友z2 小时前
别只知道暴力循环!我从用户名校验功能中领悟到的高效字符集判断法(1684. 统计一致字符串的数目)
算法
刚入坑的新人编程2 小时前
暑期算法训练.9
数据结构·c++·算法·leetcode·面试·排序算法
码事漫谈2 小时前
AGI就像暴雨,可能说来就来
算法
workflower2 小时前
数据分析前景
算法·数据挖掘·数据分析·需求分析·软件需求
阿鼎08153 小时前
揭秘大语言模型:从文字到数字,token 是如何变成向量的?
人工智能·算法