剑指offer上关于树的题目汇总

树的题目通常可以用递归解决,递归过程的本质是栈,因而理论上递归也可以用循环加堆栈(或者队列)解决

关于递归

递归非常容易让人思路混乱,看到网上有一种思路觉得很有用,就是假设子问题已经完美处理,你只需思考最终问题的处理思路,子问题的处理思路和最终问题的处理思路一样,这样思路就会清晰很多。
以下代码示例均为python版本

题目一:从上往下打印二叉树
题目描述:

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

算法思路:

很明显用层次遍历就可以解决,即广度遍历,从上往下打印,即每一层打印完之后需要按照父节点们的顺序继续打印子节点,
符合队列先进先出的特点,因而需要借助队列+循环判断就可以解决。
即借助队列,将根结点加入队列,每遍历到一个结点,将该结点移除出队列并将该结点的左右节点加入队列,重复这个过程,直至队列为空。


来源:剑指offer
关键字:队列 循环

代码如下

# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        if root is None:
            return []
        tempnode = []
        tempnode.append(root)
        valres = []
        while (len(tempnode) > 0):
            node = tempnode.pop(0)
            valres.append(node.val)
            if node.left is not None:
                tempnode.append(node.left)
            if node.right is not None:
                tempnode.append(node.right)
        return valres

题目二:二叉树的镜像
题目描述:

操作给定的二叉树,将其变换为源二叉树的镜像。
如下图:


来源:剑指offer
算法思路:

从题目可以知道二叉树的镜像其实可以看成是左右子结点交换的过程,如下图:


来源:剑指offer

因而我们在前序遍历(顺序为根子树->左子树->右子树)的基础上,交换当前结点的左右子结点,就可以完成二叉树的镜像。
代码如下

# -*- 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 root is None:
            return root
        if root.left is None and root.right is None:
            return root
        tempNode = root.left
        root.left = root.right
        root.right = tempNode
        self.Mirror(root.left)
        self.Mirror(root.right)

关键字:递归 前序遍历
题目三:二叉搜索树的后序遍历序列
题目描述:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回True,否则返回False。假设输入的数组的任意两个数字都互不相同。

算法思路:

二叉搜索树:

是指一棵空树或者具有下列性质的二叉树:

若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的结点。


来源:剑指offer

后序遍历顺序:左子树->右子树->根结点

1)递归方法
由后序遍历顺序可知,序列的最后一个元素为根结点,根据二叉搜索树的特点可知,左子树的每个非空结点都不大于根结点,右子树的每个非空结点都不小于根结点,题目中规定序列中各个结点都不重复,因此可以确定题目中给的测试用例中,左子树的每个结点势必都小于根结点,右子树的每个结点势必都大于根结点。
因此从左往右查找,找到第1个大于根结点的值则说明这个元素往左边的元素是左子树,该元素及往右边的元素到最后一个结点前为右子树。
如果左子树有任一元素大于根结点,或者右子树有任一元素小于根结点,说明该序列不为二叉搜索树遍历序列。
以此方法进行递归判断。

图片

图中最后一个元素8为根结点,元素9为从左往右序列中第一个大于根结点的值,以9往左为左子树,9和9往右到最后一个元素8前为右子树。
观察可知 如果符合二叉搜索树,则右子树序列元素都比根结点大
左右子序列以此方法递归可判断。
代码如下

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence is None or len(sequence) == 0:
            return False
        return self.VerifyBST(sequence)

    def VerifyBST(self,verifys):
        if len(verifys) <= 1:  # 只剩根结点
            return True
        root = verifys[-1]
        temps = verifys[:-1]
        lefts = []
        rights = []
        for i in range(len(temps)):
            if temps[i] > root:
                lefts = temps[0:i]
                if i <= len(temps) - 1:
                    rights = temps[i:-1]
                break
        else:
            lefts = temps
        for v in rights:
            if v < root:
                return False
        return self.VerifyBST(lefts) and self.VerifyBST(rights)

2)非递归方法(牛客网上看到的)
大致思路是根据后序遍历,将当前结点A作为根结点,遍历结点A前面序列的值,如果当前序列元素值小于结点A的值,并且前一序列元素值也大于结点A的值 说明不是二叉搜索树。

参考链接 牛客网

截图(侵删):

图片侵删

关键字:递归 二叉搜索树特点
题目四:二叉树中和为某一值的路径
题目描述:

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

算法思路:

路径指的是树的根结点到叶结点所经过的结点,因此题目其实是求从根结点到某一叶结点的路径上所有结点的和是否为题目中要求的值。
因为计算是从根结点开始,所以其实可以看成是树的前序遍历的基础上计算路径和,由于题目要求打印出路径,因而每次遍历结点需要记录下当前结点,到达叶结点时需要判断该路径是否符合条件,当递归回退到上一个结点时需要从路径中移除当前结点即路径的最后一个结点,记录路径可以用堆栈。
示例:


来源:剑指offer

根结点到叶结点加入堆栈 ,堆栈中加入序列为 10,5, 4;
10+5+4不等于22,不记录路径;
弹出4,回到父结点5,堆栈序列 10,5;
右叶结点7 进栈 ,堆栈序列 10,5,7,等于22 ,记录路径;
弹出7,回到5;
弹出5,回到10;
叶结点12进栈,堆栈序列 10,12 等于 22 ,记录路径;
所以符合条件的路径为[10,5,7]和[10,12]。

# -*- 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):
        return self.RealFindPath(root, 0, expectNumber, [], [])

    def RealFindPath(self, root, sum, expectNumber, path, allpath):
        if root is None:
            return allpath
        sum += root.val
        path.append(root.val)
        if root.left is None and root.right is None:
            if sum == expectNumber:
                allpath.append(path[:])
        if root.left:
            self.RealFindPath(root.left, sum, expectNumber, path, allpath)
        if root.right:
            self.RealFindPath(root.right, sum, expectNumber, path, allpath)
        # 回退到上个结点前弹出当前元素
        if len(path) > 0:
            num = path.pop()  # 弹出末尾元素
            sum = sum - num
        return allpath
关键字:递归 堆栈
题目五:对称的二叉树
题目描述:

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

算法思路:

递归方法:
如下图,由对称的二叉树观察得知,同一父节点的左子结点(6)的左结点(矩形1)和右子结点(6)的右结点(矩形1)如果不相等(一个为空另一个不为空也是不相等),或者同一父节点的左子结点(6)的右结点(圆形3)和右子结点(6)的左结点(圆形3)如果不相等(一个为空另一个不为空也是不相等),则说明该二叉树不为对称二叉树。


示例
# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
    
class Solution:
    def isSymmetrical(self, pRoot):
        if pRoot is None:
            return True
        return self.IsRealSymmetrical(pRoot.left, pRoot.right)

    def IsRealSymmetrical(self, Lroot, Rroot):
        if (Lroot and Rroot is None) or (Rroot and Lroot is None):
            return False
        if Lroot is None and Rroot is None:
            return True
        if Lroot.val != Rroot.val:
            return False
        return self.IsRealSymmetrical(Lroot.left, Rroot.right) and self.IsRealSymmetrical(Lroot.right, Rroot.left)

关键字:递归 非递归
题目六:重建二叉树
题目描述:

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

算法思路:

由前序序列和中序序列可得二叉树。由前序遍历的遍历过程可以知道,前序序列的第1个元素为根结点,在中序序列中找到根结点,序列中根结点往左为左子树,根结点往右为右子树。根据此方法递归可重建二叉树,递归的本质是栈(先进后出),因而最后递归返回的结点即为根结点。


来源:剑指offfer
关键字:递归

==============================
发现一个好玩的项目 ~
https://github.com/Wscats/piano

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 树 记录《剑指offer》中所有关于树的题目,以及LeetCode中的相似题目。 相关题目列表 题目 树是一种最常...
    wenmingxing阅读 1,392评论 2 13
  • 目录 1、什么是树 2、相关术语 3、二叉树 3.1、二叉树的类型 3.2、二叉树的性质 3.3、二叉树的结构 3...
    我哈啊哈啊哈阅读 2,523评论 0 10
  • 数据结构和算法--二叉树的实现 几种二叉树 1、二叉树 和普通的树相比,二叉树有如下特点: 每个结点最多只有两棵子...
    sunhaiyu阅读 6,404评论 0 14
  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,624评论 0 13
  • 文/向上 秋风, 你带着许多尘沙, 吹过我。 让我的伤感被你带走吧! 秋雨, 你带着许多苦泪, 淋过我。 让我流出...
    A向上阅读 1,797评论 32 77