剑指offer(Python版)——23-28

23.二叉搜索树的后序遍历

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

解题思路:遇到二叉树,首先应该想的是递归来解决,因为它的结构太对称了。二叉搜索树,左子树的节点值都小于根节点值,根节点值都小于右子树的节点值。后序遍历的过程是左子树,右子树,根节点。二叉搜索树的后序遍历得到的序列就满足这几个特性。第一,最后一个值是根节点的值,其次,从序列的第一个值开始,遇到的第一个大于根节点值之前的值都是左子树的,剩下的到根节点之前都是右子树的。这样就把整个二叉树的框架搭建起来了,分清了左子树、右子树,根节点。在每个子树里采取同样的操作递归执行,就可以将左右子树构建为二叉树。递归中,主要的区别就是底层的判断设计,这里是判断是否是后序遍历,则在最底层时,只剩一个节点,直接返回真。

代码如下:

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if not sequence:
            return False
        if len(sequence) == 1:
            return True
        i = 0
        # 寻找比根节点大的第一个值
        while (sequence[i] < sequence[len(sequence)-1]):
            i += 1
        r_1 = sequence[i]
        j = i
        # 判断左子树所有节点是否比根节点小
        while (j < len(sequence)-1):
            if sequence[j] < sequence[-1]:
                return False
            else:
                j += 1
        # 设置标志来记录左右子树是否是后序遍历
        left = True
        right = True
        # 递归的判断左右子树
        if len(sequence[0:i]) > 0:
            left = self.VerifySquenceOfBST(sequence[0:i])
        if len(sequence[i:len(sequence)-1]) > 0:
            right = self.VerifySquenceOfBST(sequence[i:len(sequence)-1])
    return left and right

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

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

解题思路:二叉树,先考虑递归解决,同样可以拆分分成左右子树递归去做,找出左子树中满足值减去根节点值得所有路径,右子树也是同样,这样将根节点和左右子树所有满足条件的序列组合,就是最终的所有路径。所有路径都放在list中,所以递归的底层是判断是否满足是叶节点并且值和传递进来的相等。

代码如下:

# -*- 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
        # 按递归的方法,主要讲递归最底层的判断条件写清楚就好了
        if not root :
            return []
        if root and not root.left and not root.right and root.val == expectNumber:
            return [[root.val]]
        result = []
        # 递归的判断左右子树
        re_left = self.FindPath(root.left,expectNumber-root.val)
        re_right = self.FindPath(root.right,expectNumber-root.val)
        # 将左右子树中的所有路径与根节点合并为最终路径
        for i in re_left + re_right:
            result.append([root.val]+i)
        return result

25.复杂链表的复制

题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

解题思路:三段式解法,第一步现将链表每个节点在原链表中复制一个节点,这样链表就变成了原来的二倍,但是扩充的节点只有next指针,随机指针为空;第二步,将链表中原来节点的随机指针进行复制,新链表节点的随机指针等于原链表节点随机指向节点的next指针。第三步,链表拆分成两个链表,使用两个指针交替改变节点指向,最后得到拆分链表。复制next指针和随机指针的结构很类似,拆分链表时注意两个指针交替进行即可

代码如下:

# -*- 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
        self.CloneNode(pHead)
        self.ConnectRandomNode(pHead)
        return self.ReconnctNode(pHead)
    def CloneNode(self,pHead):
		# 将链表进行复制
        pNode = pHead
        while (pNode):
            pCloneNode = RandomListNode(pNode.label)
            pCloneNode.next = pNode.next
            pNode.next = pCloneNode
            pNode = pCloneNode.next
    def ConnectRandomNode(self,pHead):
	    # 复制节点随机指针
        pNode = pHead
        while (pNode):
            pClone = pNode.next
            if pNode.random :
                pClone.random = pNode.random.next
            pNode = pClone.next
    def ReconnctNode(self,pHead):
		# 拆分链表
        pNode = pHead
        pCloneHead = None
        pCloneNode = None
        if pNode:
            pCloneHead = pCloneNode = pNode.next
            pNode.next = pCloneNode.next
            pNode = pNode.next
        while (pNode):
            pCloneNode.next = pNode.next
            pCloneNode = pCloneNode.next
            pNode.next = pCloneNode.next
            pNode = pNode.next
        return pCloneHead

 

26.二叉搜索树与双向链表

题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

解题思路:二叉树,先考虑递归去解决。将二叉搜索树转变成双向链表只要将二叉搜索树的节点指针变成中序遍历的序列指向即可。还是先在左子树,根节点,右子树上考虑。中序的序列中,根节点前面的节点是左子树中最大的,根节点后面的节点是右子树中最小的节点。掌握了这个特性,可以先将左子树递归,然后取出左子树列表的最大的,也是最右端的节点,修改指针。右子树类似操作。最后将整个双向列表的头结点返回(最左边的节点)

代码如下:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Convert(self, pRootOfTree):
        # 采用递归的方法,去解决左右子树
        # 根节点和左子树最大的节点相连,和右子树最小的节点相连
        if not pRootOfTree:
            return pRootOfTree
        if not pRootOfTree.left and not pRootOfTree.right:
            return pRootOfTree
        # 递归处理左子树,con_left是转化成链表后的左子树部分
        self.Convert(pRootOfTree.left)
        conv_left = pRootOfTree.left
        # 寻找左子树最大的节点与根节点相连
        if conv_left:
            while(conv_left.right):
                conv_left = conv_left.right
            conv_left.right,pRootOfTree.left = pRootOfTree,conv_left
        # 递归处理右子树
        self.Convert(pRootOfTree.right)
        conv_right  = pRootOfTree.right
        if conv_right:
            while(conv_right.left):
                conv_right = conv_right.left
            conv_right.left,pRootOfTree.right = pRootOfTree,conv_right
        # 找到调整后的头结点
        while(pRootOfTree.left):
            pRootOfTree = pRootOfTree.left
        return pRootOfTree

 

27. 字符串的排列

题目:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。(输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。)

解题思路:递归的思路,序列分成两部分,第一个字符是一部分,之后的所有字符是一部分。我只要求出第二部分所有的排列加上第一个部分就是以第一部分开头的所有序列。将第一部分和后面每个字符调换位置,再采用同样的处理方式就可以得到其他字符开头的所有排列。

代码如下: 

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        if not ss:
            return []
        if len(ss) == 1:
            return ss
        result = []
        list_ss = list(ss)
        for i in list_ss:
            temp = list_ss[:]
            temp.remove(i)
            for j in self.Permutation(''.join(temp)):
                result.append(i+j)
        return sorted(list(set(result)))

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值