牛客网——python之剑指0ffer之67道在线编程——jz21-jz25

剑指0ffer—67道在线编程—jz21~jz25

  • jz21 栈的压入、弹出序列
  • jz22 从上往下打印二叉树
  • jz23 二叉搜索树的后序遍历序列
  • jz24 二叉树中和为某一值的路径
  • jz25 复杂链表的复制

jz21 栈的压入、弹出序列

题目描述

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

思路分析:

借用一个列表式的辅助栈stack,遍历压栈顺序,先讲第一个,入栈序列中的第一个元素放入栈stack中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:判断4,5,3,2,1是否为入栈顺序为1,2,3,4,5的栈的弹出顺序

入栈顺序1,2,3,4,5

出栈顺序4,5,3,2,1

首先1入辅助栈stack,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4即删除栈stack末尾元素,弹出序列向后一位即此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。

【代码实现】

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        #如果压入栈序列为空或两个序列不等,则直接False
        if not pushV or len(pushV)!=len(popV):
            return False
        #创建一个列表式的辅助栈
        stack=[]
        for i in pushV:
            #将pushV栈内元素依次列表格式的stack内
            stack.append(i)
            #while循环比较,比较stack新加元素、popV的首位元素,若相等,则停止添加
            print('开始比较:',stack[-1],popV[0])
            while len(stack)and stack[-1]==popV[0]:
                #然后将满足条件的两个元素各自删除!继续比较下一个相同元素
                print('执行移除操作!',stack[-1],popV[0])
                stack.pop()#默认删除最后一个元素
                popV.pop(0)
        if len(stack):#如果辅助列表不为空
            return False
        return True

jz22 从上往下打印二叉树

题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

题目链接

思路分析:

此题相当于树的层序遍历:从二叉树的第一层(即根结点)开始,从上至下逐层遍历,则按从左到右的顺序对结点逐个访问。

层序遍历即广度优先遍历,用队列的方式实现。

层序遍历伪代码: 以队列的方式进行

1.队列Q初始化;
2.如果二叉树为空,将根指针入队;
3.循环直至队列Q为空

  • 3.1 q=队列Q的队头元素出队;
  • 3.2 访问结点q的数据域;
  • 3.3若结点q存在左孩子,则将左孩子指针入队;
  • 3.4若结点q存在右孩子,则将右孩子指针入队;

【代码实现】

# -*- 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):
        # write code here
        tree_list=[]#创建空列表,以存放节点
        if not root:
            return []
        q=[root]#将二叉树根结点转换成队列即列表的形式
        while len(q):#当子根不再有子节点时,结束循环
            t=q.pop(0)
            tree_list.append(t.val)
            if t.left:#左子树
                q.append(t.left)
            if t.right:#右子树
                q.append(t.right)
        return tree_list
        
        
        

jz23 二叉搜索树的后序遍历序列

题目描述

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

题目链接

思路分析:

1、后序遍历:左子树–>右子树–>根结点
后序遍历结果的最后一个元素就是当前二叉树的根元素。
2、二叉搜索树的特点:
二叉搜索树:是一颗二叉树,可能为空;
一颗非空的二叉搜索树满足以下特征:

  • 1.每个元素有一个关键字,并且任意两个元素的关键字都不同;因此所有的关键字都是唯一的。
  • 2.在根节点的左子树中,元素的关键字(如果有的话)都小于根节点的关键字。
  • 3.在根节点的右子树中,元素的关键字(如果有的话)都大于根节点的关键字。
  • 4.根节点的左右子树也是二叉搜索树。

【代码实现】

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        #1、先判断长度,0返回False,1返回True
        length=len(sequence)
        if length==0:
            return False
        if length==1:
            return True
        #2、两个for循环判断,左右子树和根结点值比较
        root=sequence[length-1]#后序遍历的最后一个值,就是根结点
        for i in range(length):
            if sequence[i]>root:#后序遍历中,左子树节点小于根结点
                break #若是嵌套循环,break语句将停止执行最深层的循环,并开始执行下一行代码
        for j in range(i,length):
            if sequence[j]<root:#后序遍历中,右子树的节点都大于根结点
                return False
        #3、两个if语句判断左右子树是否为二叉树
        #判断左子树是否为二叉搜索树
        left=True
        if i>0:
            left=self.VerifySquenceOfBST(sequence[0:i])
        
        #判断右子树是否为二叉树
        right=True
        if i<length-1:
            right=self.VerifySquenceOfBST(sequence[i:-1])
        return left and right 


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

题目描述

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

牛客网——python之剑指0ffer之67道在线编程——jz21-jz25_第1张图片

题目链接

思路分析:

  • 首先清楚叶子的表示:如果节点为root, 那么当前节点为叶子节点的必要条件为没有左孩子与右孩子。
  • 找出路径,当然需要遍历整棵树,这里采用先序遍历,即:根节点,左子树,右子树

解题步骤:
1、首先判断,是否存在根结点,如果没有根结点,则返回空
2、若存在根结点

  • 如果根结点没有左孩子与右孩子,则根结点相当于叶子节点,若根结点的值与期望值相同,则保留该路径,返回根结点的值。
  • 如果根结点有左孩子与右孩子,则递归更新左孩子与右孩子,其期望值为原期望值减去根结点的值。

【代码实现】

# -*- 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
        #1、判断是否存在根结点
        if not root:
            return []
        #2、如果根结点没有左孩子、右孩子,则根结点相当于叶子结点,
        #同时,若根结点的值等于期望值,则保留该路径
        if root and not root.left and not root.right and root.val==expectNumber:
            return [[root.val]]
        #创建空列表,存储满足条件的路径
        res=[]
        #3、递归更新左子树、右子树:期望值-根结点之后,作为下一轮期望值,进行递归求解。
        left=self.FindPath(root.left, expectNumber-root.val)
        right=self.FindPath(root.right, expectNumber-root.val)
        #4、for循环,将满足条件的路径添加到res列表中。
        for i in left+right:
            res.append([root.val]+i)
        return res
        

jz25 复杂链表的复制

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

题目链接

思路分析:

【代码实现】

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        #先判断是否存在
        if not pHead:
            return pHead
        #定义next、random
        p=RandomListNode(pHead.label)
        p.next=pHead.next
        p.random=pHead.random
        #递归
        p.next=self.Clone(pHead.next)
        return p

未完待续

你可能感兴趣的