【算法题】剑指offer之二叉树--python实现

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

在这里插入图片描述
二叉搜索树
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。

在这里插入图片描述
后续遍历结果:1 5 3 9 12 10 7
二叉搜索树的后续遍历具有以下特点:

  • 最后一个元素为数的根节点
  • 存个一个分界线,分界线左边的所有元素都小于根节点,分界线右边的所有元素都大于根节点(上图的分界线就在3 9 之间)
  • 经过第二步的分割,形成两个切片[1 5 3]、[9,12,10],切片同样符合上述规律

根据上面的特点,在考虑两种特殊情况,1.无左孩子,2.无右孩子

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if not sequence:
            return False
        if len(sequence) == 1:
            return True
        count1 = 0
        count2 = 0
        for i in range(len(sequence)):
            #左右孩子节点都不为空
            if sequence[i] < sequence[-1] and sequence[i+1] > sequence[-1]:
                #左子树的所有节点必须小于根节点
                for j in range(i+1):
                    if sequence[j] > sequence[-1]:
                        return False
                #右子树所有节点必须大于根节点
                for k in range(i+1,len(sequence)-1):
                    if sequence[k] < sequence[-1]:
                        return False
                return self.VerifySquenceOfBST(sequence[:i+1]) and self.VerifySquenceOfBST(sequence[i+1:-1])
            #仅有左孩子
            if sequence[i] < sequence[-1]:
                count1 += 1
            #仅有右孩子
            if sequence[i] > sequence[-1]:
                count2 += 1 
            if count1 == len(sequence)-1 or count2 == len(sequence)-1:
                return self.VerifySquenceOfBST(sequence[:-1])
        return False

从上往下打印二叉树–广度遍历

在这里插入图片描述

# -*- 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
        answer = []
        if not root:
            return answer
        li = [root]
        while li:
            cur = li.pop(0)
            answer.append(cur.val)
            if cur.left:
                li.append(cur.left)
            if cur.right:
                li.append(cur.right)
        return answer

重建二叉树

在这里插入图片描述

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        root = TreeNode(pre[0])
        # i = tin.index(pre[0])
        #
        # tin_lchild = tin[:i]
        # len_lchild = len(tin_lchild)
        # pre_lchild = pre[1:1+len_lchild]
        #
        # tin_rchild = tin[i+1:]
        # len_rchild = len(tin_rchild)
        # pre_rchild = pre[1+len_lchild:]
        root.left = self.reConstructBinaryTree(pre[1:1+len(tin[:tin.index(pre[0])])], tin[:tin.index(pre[0])])
        root.right = self.reConstructBinaryTree(pre[1+len(tin[:tin.index(pre[0])]):], tin[tin.index(pre[0])+1:])
        return root

笔记
递归★★★★★

class soultion:
    def nove(self,n,a,b,c):
        print(n,a,b,c)
        if n == 1:
            print(a,'------------>',c)
        else:
            self.nove(n-1,a,c,b)
            self.nove(1,a,b,c)
            self.nove(n-1,b,a,c)
if __name__ == "__main__":
    a = soultion()
    b = a.nove(3, 'A', 'B', 'C')
    print(b)

上述程序的执行结构图如下所示:
在这里插入图片描述
四个字母分别代表传入的(n,a,b,c)
传入顺序:由左到右,由上到下。

判断对称二叉树

在这里插入图片描述

# -*- 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
        if pRoot is None:
            return True
        return self.check(pRoot.left,pRoot.right)
    def check(self,l,r):
        if l == None and r == None:
            return True
        elif (l != None and r == None) or (l == None and r != None) or (l.val != r.val):
            return False
        return self.check(l.left,r.right) and self.check(l.right,r.left)

二叉树的下一个节点

在这里插入图片描述
题目分析
在这里插入图片描述
在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        #有右子树
        if pNode.right != None:
            r = pNode.right
            while r.left:
                r = r.left
            return r
        #无右子树
        else:
            #如果是根节点(无父节点)
            if pNode.next == None:
                return None
            #如果不是根节点(有父节点)
            else:
                #如果是父节点的左孩子
                if pNode == pNode.next.left:
                    return pNode.next
                #如果是父节点的右孩子
                else:
                    while pNode.next.next.left != pNode.next:
                        pNode = pNode.next
                        #没有符合条件的即是尾节点
                        if pNode.next.next == None:
                            return None
                    return pNode.next.next
                

把二叉树打印成多行

在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        #用两个列表分别保存当前行节点和下一行节点
        current = [pRoot]
        next_layer = []
        result = []
        if pRoot is None:
            return result
        while current:
            for i in current:
                if i.left:
                    next_layer.append(i.left)
                if i.right:
                    next_layer.append(i.right)
            #每一层输出一行,重点在于下面的append([]),[]就表示了每层一行
            result.append([i.val for i in current])
            current,next_layer = next_layer,[]
        return result

按之字形顺序打印二叉树

在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        # write code here
        current = [pRoot]
        next_layer = []
        result = []
        deep = 0
        if pRoot is None:
            return result
        while current:
            deep += 1
            for i in current:
                if i.left:
                    next_layer.append(i.left)
                if i.right:
                    next_layer.append(i.right)
            if deep % 2 != 0:
                result.append([i.val for i in current])
            else:
                #下面这两句话的含义是一样的,都是逆序遍历current[]
                #result.append([current[len(current)-i-1].val for i in range(len(current))])
                result.append([i.val for i in current[::-1]])
            current,next_layer = next_layer,[]
        return result

序列化二叉树

在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.count = -1
    def Serialize(self, root):
        # write code here
        # 下面的两种判断方式相同
        # if root is None:
        if not root:
            #必须添加分隔符,否则两位数转化为字符串时会出现错误
            return "#,"
        #如果当前节点是父节点,则会继续递归
        #如果当前节点是叶节点,则会返回“.val , # , #"
        return str(root.val)+ ',' + self.Serialize(root.left) + self.Serialize(root.right)
    def Deserialize(self, s):
        # write code here
        self.count += 1
        #只是第一次进入函数时对字符串进行分割
        #split操作返回的是一个列表,如果每次都进行split操作会报错
        #因为第一次往后s变成了列表,列表没有split操作
        if self.count == 0:
            s = s.split(',')
        if self.count >= len(s):
            return None
        root = None
        if s[self.count] != "#":
            root = TreeNode(int(s[self.count]))
            root.left = self.Deserialize(s)
            root.right = self.Deserialize(s)
        return root

split示例
在这里插入图片描述

二叉搜索树的第k个结点

在这里插入图片描述
二叉搜索树
二叉搜索树也叫二叉排序树,它可以是一棵空树。它具有一下特点

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树
  • 没有键值(key)相等的节点
  • 二叉搜索树的中序遍历结果是排好序的

二叉搜索树如下所示:
在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def __init__(self):
        self.li = []
        self.serch_flag = False
        self.node = None

    def KthNode(self, pRoot, k):
        # write code here
        if k <= 0 or  not pRoot:
            return None
        self.li = self.Tinorder(pRoot)
        if len(self.li) < k:
            return None
        self.node = self.Serch(pRoot, self.li[k - 1])
        return self.node
    #二叉搜索树的中序遍历结果是排序好的
    def Tinorder(self, pRoot):
        """中序遍历"""
        if not pRoot:
            return
        self.Tinorder(pRoot.left)
        self.li.append(pRoot.val)
        self.Tinorder(pRoot.right)
        return self.li

    def Serch(self, pRoot, num):
        """数值搜索"""
        if not pRoot:
            return
        if pRoot.val == num:
            self.node = pRoot
        self.Serch(pRoot.left,num)
        self.Serch(pRoot.right,num)
        return self.node

本题扩展–任意二叉树的第K个节点

思路:

  • 首先利用前序遍历将二叉树存入列表
  • 再对列表进行快速排序
  • 然后在寻找节点
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def __init__(self):
        self.li = []
        #self.serch_flag = False
        self.node = None

    def KthNode(self, pRoot, k):
        # write code here
        if k <= 0 or  not pRoot:
            return None
        self.li = self.Perorder(pRoot)
        if len(self.li) < k:
            return None
        self.li = self.Quick_sort(self.li, 0, len(self.li) - 1)
        self.node = self.Serch(pRoot, self.li[k - 1])
        return self.node

    def Perorder(self, pRoot):
        """先序遍历"""
        if not pRoot:
            return
        self.li.append(pRoot.val)
        self.Perorder(pRoot.left)
        self.Perorder(pRoot.right)
        return self.li

    def Quick_sort(self, alist, first, last):
        """快速排序"""
        # 终止条件
        if first >= last:
            return alist
        mid_value = alist[first]
        low = first
        high = last
        while low < high:
            while low < high and alist[high] >= mid_value:
                high -= 1
            alist[low] = alist[high]
            while low < high and alist[low] < mid_value:
                low += 1
            alist[high] = alist[low]
        alist[low] = mid_value

        self.Quick_sort(alist, first, low - 1)

        self.Quick_sort(alist, low + 1, last)
        return alist
    def Serch(self, pRoot, num):
        """数值搜索"""
        if not pRoot:
            return
        if pRoot.val == num:
            #self.serch_flag = True
            self.node = pRoot

        self.Serch(pRoot.left,num)
        self.Serch(pRoot.right,num)
        return self.node

数据流中的中位数

在这里插入图片描述
方法一–锥排序

思路:

  • 建立一个大顶锥,一个小顶锥,小顶锥用来存大的半数数据,大顶锥用来存小半数数据(小顶堆中的元素都大于等于大顶堆中的元素)
  • 当数目为偶数的时候,将这个值插入大顶堆中,再将大顶堆中根节点(即最大值)插入到小顶堆中
  • 当数目为奇数的时候,将这个值插入小顶堆中,再将小顶堆中根节点(即最小值)插入到大顶堆中
  • 取中位数的时候,如果当前个数为偶数,显然是取小顶堆和大顶堆根结点的平均值;如果当前个数为奇数,显然是取小顶堆的根节点
# -*- coding:utf-8 -*-
#导入优先队列算法
from heapq import *
#在heapq中只有小顶锥,大顶锥则用取反实现
class Solution:
    def __init__(self):
        #创建一个堆,可以使用list来初始化为 []
        self.heaps = [], []
        self.count = 0
    def Insert(self, num):
        # write code here
        small, large = self.heaps
        if self.count % 2 == 0:
            #heapq.heappush(heap, item)
            #将 item 的值加入 heap 中,保持堆的不变性。
            #heapq.heappushpop(heap, item)
            #将 item 放入堆中,然后弹出并返回 heap 的最小元素。
            """
            如果是偶数:
            先将取反放入大顶锥
            再将大顶锥的追锥顶pop出,并取反放入小顶锥
           (由于大顶锥用来存小半数数据,且大顶锥是小顶锥取反实现,
            因此大顶锥里面的数全为原始数据的相反数)
            """
            #-num的负号表示大顶锥里面的数全为原始数据的相反数
            #-heappushpop的负号表示小顶锥里面的数全为原始数据(即相反数的相反数)
            heappush(small, -heappushpop(large, -num))
        else:
            """
            如果是奇数:
            先将放入小顶锥
            再将大顶锥的追锥顶pop出,并取反放入大顶锥
            """
            heappush(large, -heappushpop(small, num))
        self.count+=1
    def GetMedian(self,ss):
        # write code here
        small,large = self.heaps
        if self.count % 2 != 0:
            return float(small[0])
        return (small[0] - large[0]) / 2.0

方法二

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        #用来记录数据流的个数
        self.count = 0
        self.li = []
    def Insert(self, num):
        # write code here
        self.li.append(num)
        self.li.sort()
        self.count+=1
    #题目有问题,缺少一个参数。需要自己加上
    def GetMedian(self,AA):
        # write code here
        if self.count % 2 == 0:
            #牛客网python版本为2+,被除数需要写成小数形式
            #python2    5/2 = 2
            #python3    5/2 = 2.5
            return (self.li[self.count//2-1]+self.li[self.count//2])/2.0
        else:
            return self.li[self.count//2]

树的子结构

在这里插入图片描述

# -*- 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
        result = False
        if pRoot1 != None and pRoot2 != None:
            if pRoot1.val == pRoot2.val:
            #此方法中下面的语句可以用下面的这一句话代替
            #    return self.Perorder(pRoot1,pRoot2) or self.HasSubtree(pRoot1.left,pRoot2) or self.HasSubtree(pRoot1.right,pRoot2)
                result = self.Perorder(pRoot1,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right,pRoot2)
        return result
            
    def Perorder(self, pRoot1, pRoot2):
        if not pRoot2:
            return True
        if not pRoot1:
            return False
        #下面的四句话可以写成
        #if pRoot1.val != pRoot2.val:
        #    return False
        #return self.Perorder(pRoot1.left,pRoot2.left) and self.Perorder(pRoot1.right,pRoot2.right)
        if pRoot1.val == pRoot2.val:
            return self.Perorder(pRoot1.left,pRoot2.left) and self.Perorder(pRoot1.right,pRoot2.right)
        else:
            return False

二叉树的镜像

在这里插入图片描述
在这里插入图片描述

# -*- 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
        if root.left or root.right:
            root.left,root.right = root.right,root.left
        self.Mirror(root.left)
        self.Mirror(root.right)
        return root

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

在这里插入图片描述
叶节点:没有子节点的节点
思路:
用一临时列表记入当前先序遍历的整条路径,若此路径节点值的和等于expectNumber,则将路径加入最终返回的列表之中。
注意:当一父节点的两个子节点所在的路径都遍历完时,需要将父节点从临时列表中删除。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def __init__(self):
        self.li = []
        #用于保存遍历的路径
        self.tem = []
    def FindPath(self, root, expectNumber):
        # write code here
        #当root为空时,直接返回空列表
        if not root:
            return self.li
        #当此节点为叶节点,开始判断sum(self.tem)是否等于expectNumber
        if not root.left and not root.right:
            self.tem.append(root.val)
            if sum(self.tem) == expectNumber:
                self.li.append(self.tem)
                #数组长度大于1时,才能进行下面的切片操作
                #当self.tem = self.tem[:-1]用self.tem.pop()代替时,会出现问题
                if len(self.tem) > 1:
                    self.tem = self.tem[:-1]
            else:
                self.tem.pop()
            return self.li
        #下面三句话相当前序遍历
        self.tem.append(root.val)
        if root.left:
            self.FindPath(root.left, expectNumber)
        if root.right:
            self.FindPath(root.right, expectNumber)
        #遍历完一次,返回上一层时需要将父节弹出
        self.tem.pop()
        return self.li

二叉树与双向链表

在这里插入图片描述
思路
二叉搜索树的中序遍历为排序列表
在中序遍历的基础上进行稍微改动即可。

#二叉搜索树的中序遍历为排序列表
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.last_node = None
    def Convert(self, pRootOfTree):
        # write code here
        self.Tinorder(pRootOfTree)
        while pRootOfTree and pRootOfTree.left:
            pRootOfTree = pRootOfTree.left
        return pRootOfTree
    
    def Tinorder(self,cur):
        if not cur:
            return
        self.Tinorder(cur.left)
        #当前节点的左节点指向上一节点
        cur.left = self.last_node;
        #只有当上一个节点不为空时,上一节点的右节点才能指向当前节点
        if self.last_node:
             self.last_node.right = cur;
        self.last_node = cur;
        self.Tinorder(cur.right)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值