【剑指offer26-34】二叉树相关习题+Python代码

文章目录

    • 26.树的子结构
    • 27.二叉树的镜像
    • 28.对称的二叉树
    • 29.顺时针打印矩阵
    • 30.包含min的栈
    • 31.栈的压入、弹出序列
    • 32.从上到下打印二叉树
    • 33.二叉搜索树的后序遍历序列
    • 34.二叉树中和为某一值的路径

26.树的子结构

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

子结构可以是树的任意一部分。

  • 解题思路
  1. 在A中查找和B根节点一样值的点,有一样的进入到第2步,不一样继续递归遍历树的左右子树。
  2. 根节点一样了,继续判断左右子树,这时要注意判断A和B为空的情况。
class Solution:
    def HasSubtree(self, p1, p2):
        result=False
        if p1!=None and p2!=None:
            if p1.val==p2.val:
                result=self.issubstruct(p1,p2)
            if not result:
                result=self.HasSubtree(p1.left,p2)
            if not result:
                result=self.HasSubtree(p1.right,p2)
        return result
    def issubstruct(self,p1,p2):
        if not p2:
            return True
        if not p1:
            return False
        if p1.val!=p2.val:
            return False
        return self.issubstruct(p1.left,p2.left) and self.issubstruct(p1.right,p2.right)

27.二叉树的镜像

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

输入描述:
二叉树的镜像定义:源二叉树

            8
           /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5

【剑指offer26-34】二叉树相关习题+Python代码_第1张图片

  • 求一棵树的镜像的过程:先前序遍历这棵树的每个节点,如果遍历到的节点有子节点,就交换它的两个子节点,当交换完所有非叶节点的左右子节点之后,就得到了树的镜像。
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        if not root:
            return root
        if not root.left and not root.right:
            return root
        temp=root.right
        root.right=root.left
        root.left=temp
        if root.left:
            self.Mirror(root.left)
        if root.right:
            self.Mirror(root.right)
        return root

28.对称的二叉树

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

【剑指offer26-34】二叉树相关习题+Python代码_第2张图片

在这里针对前序遍历定义一种对称的遍历方式,即先遍历父节点,再遍历它的右子节点,最后再遍历左子节点。

如上图1,前序遍历序列为{8,6,5,7,6,7,5}。用定义的针对前序遍历的对称遍历算法,得到的遍历序列为{8,6,5,7,6,7,5}。即这两个序列是一样的。

第二棵树的前序遍历序列为{8,6,5,7,9,7,5},而相应的对称前序遍历序列为{8,9,5,7,6,7,5}。两个序列的第二步和第五步是不一样的。

第三棵树有些特殊,所有节点的值都是一样的,前序和对称前序遍历都是{7,7,7,7,7,7},但显然第三棵二叉树不是对称的。这时需要把遍历过程中遇到的空指针也考虑进来。这时第三棵树的前序遍历为{7,7,7,null,null,7,null,null,7,7,null,null.null}。前序的对称遍历序列为{7,7,null,7,null,null,7,7,null,null,7,null,null}。这两个序列从第三步开始就不一致了。

  • 算法注意点
    新定义函数名称是不一样的
class Solution:
    def isSymmetrical(self, pRoot):
        return self.IsSymmetrical(pRoot,pRoot)
    def IsSymmetrical(self,pRoot1,pRoot2):
        if not pRoot1 and not pRoot2:
            return True
        if not pRoot1 or not pRoot2:
            return False
        if pRoot1.val!=pRoot2.val:
            return False
        return self.IsSymmetrical(pRoot1.left,pRoot2.right) and self.IsSymmetrical(pRoot1.right,pRoot2.left)

29.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

  • 解题思路:
    输出第一行之后,将矩阵逆时针旋转,在输出再旋转……
  • 算法注意点
  1. a.reverse(),将列表元素反向输出
  2. 注意not a和a==None是不一样的,在Python中not是逻辑判断词,用于布尔型True和False,而None;False;所有值为0的数:0、0.0、0L、0.0+0.0j, ‘’(空字符串)、[] (空列表)、()(空元组)、{}(空字典)这些的值都为False
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        result=[]
        while matrix:
            result+=matrix.pop(0)
            if not matrix:
                break
            matrix=self.turn(matrix)
        return result
    def turn(self,matrix):
        row=len(matrix)
        column=len(matrix[0])
        a=[]
        for i in range(column):
            b=[]
            for j in range(row):
                b.append(matrix[j][i])
            a.append(b)
        a.reverse()
        return a

30.包含min的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

第一反应可能是每次压入一个新元素进栈时,将栈里的所有元素排序,让最小的元素位于栈顶,这样就能在O(1)时间内得到最小元素了。但这不能保证后进先出,违背了栈的定义。

那么给栈添加一个成员变量存放最小的元素,每次压入一个新的元素的时候,如果该元素比当前元素小,则更新最小元素。然后当最小元素被弹出了,如何得到下一个最小元素?

我们可以把每次的最小元素(之前的最小元素和新入栈元素的最小值)都保存起来放到另外一个辅助栈。

【剑指offer26-34】二叉树相关习题+Python代码_第3张图片

  • 算法注意点:
    通过__ init __函数新建两个列表
class Solution:
    def __init__(self):
        self.stack=[]
        self.minstack=[]
    def push(self, node):
        self.stack.append(node)
        if not self.minstack or node<=self.minstack[-1]:
            self.minstack.append(node)
        else:
            self.minstack.append(self.minstack[-1])
    def pop(self):
        if not self.minstack or not self.stack:
            return None
        self.minstack.pop()
        self.stack.pop()
    def top(self):
        return self.stack[-1]
    def min(self):
        return self.minstack[-1]

31.栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

  • 解题思路:
    建立一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数字。

以弹出序列{4,3,5,1,2}为例,第一个希望被弹出的是4,因此4需要被压入辅助栈,压入栈的顺序由压栈序列确定,也就是在把4压入栈之前,数字1,2,3需要先入栈。此时栈里包含4个数1,2,3,4,4位于栈顶。把4弹出栈后,剩下1,2,3。接下来希望5被弹出,由于他不是栈顶数字,所以把第一个序列4之后一直到5的元素压入辅助栈。5位于栈顶就可以弹出了,接下来被弹出的3个数字依次是3、2、1.由于每次操作都位于栈顶,可以直接弹出。

如果到最后第二个序列不为空,而第一个序列已经为空了,就说明不是弹出序列。

  • 算法注意点:
    a.pop()弹出列表的最后一个元素,a.pop(i)弹出第i个元素
class Solution:
    def IsPopOrder(self, push, pop):
        stack=[]
        while pop:
        # 如果第一个元素都相同,就直接弹出,压入栈为空还是要比的,一开始为空,是个问题,但是压空了就要比弹出了,第二个elif
            if push and push[0]==pop[0]:
                push.pop(0)
                pop.pop(0)
            # 如果stack中最后一个元素和popV中第一个元素相同,这就是压完了之后弹出的过程中进行的比较
            elif stack and pop[0]==stack[-1]:
                stack.pop()
                pop.pop(0)
            elif push:
                stack.append(push.pop(0))
            else:
                return False
        return True

32.从上到下打印二叉树

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

  • 解题思路

按层遍历——先打印根节点,接下来要打印值为8的两个子节点,在遍历时把值为6和10的两个节点保存到一个容器里。按照从左到右的顺序,先取出值为6的点,打印值6后,把他的两个子节点5,7放入容器。如此下去,直到没有子节点了。

运用队列的先进先出。

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

33.二叉搜索树的后序遍历序列

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

  • 二叉搜索树(二叉排序树),或者是一棵空树,或者具有下列性质:若它的左子树不空,则左子树上的所有节点值均小于它的根节点的值,若它的右子树不空,则右子树上的所有节点的值均大于它的根节点的值,它的左右子树也分别为二叉排序树。
class Solution:
    def VerifySquenceOfBST(self, q):
        if not q:
            return False
        i=0
        root=q[-1]
        for node in q[:-1]:
            if node>root:
                break
            i+=1
        for node in q[i:-1]:
            if node<root:
                return False
        left=True
        if i>0:
            left=self.VerifySquenceOfBST(q[:i])
        right=True
        if i<len(q)-2 and left:
            right=self.VerifySquenceOfBST(q[i+1:])
        return left and right

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

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

  • 解题思路
    当用前序遍历的方式访问到某一节点时,我们把该节点添加到路径上,并累加该节点的值。如果该节点为叶节点,并且路径中节点值的和刚好等于输入的整数,则输出该路径。如果当前节点不是叶节点,则继续访问它的子节点。当前节点访问结束后,递归函数自动回到它的父节点。因此,我们在函数推出之前要在路径上删除当前节点并减去当前节点的值。
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def __init__(self):
        self.stack=[]
        self.result=[]
    def FindPath(self, root, num):
        if not root:
            return []
        self.stack.append(root.val)
        num-=root.val
        if num==0 and root.left==None and root.right==None:
            self.result.append(self.stack[:])
        elif num>0:
            self.FindPath(root.left,num)
            self.FindPath(root.right,num)
        self.stack.pop()
        return self.result

你可能感兴趣的:(【剑指offer26-34】二叉树相关习题+Python代码)