zoukankan      html  css  js  c++  java
  • 剑指offer-二叉树

    1. 平衡二叉树

    输入一棵二叉树,判断该二叉树是否是平衡二叉树。

    解:

    要么是一颗空树,要么左右子树都是平衡二叉树且左右子树深度之差不超过1

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def IsBalanced_Solution(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return True
    11         res = abs(self.getDepth(pRoot.left) - self.getDepth(pRoot.right))
    12         if res <= 1 and self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right):
    13             return True
    14         return False
    15         
    16     def getDepth(self, root):
    17         if not root:
    18             return 0
    19         if not (root.left or root.right):
    20             return 1
    21         return max(self.getDepth(root.left), self.getDepth(root.right)) + 1
    View Code

      

    2. 二叉树的深度

    输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

    解:

    层次遍历,bfs 实现

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def TreeDepth(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return 0
    11         depth = 0
    12         queue = [pRoot]
    13         while queue:
    14             tmp = []
    15             for i in range(len(queue)):
    16                 node = queue.pop(0)
    17                 tmp.append(node.val)
    18                 if node.left:
    19                     queue.append(node.left)
    20                 if node.right:
    21                     queue.append(node.right)
    22             if tmp:
    23                 depth += 1
    24         return depth
    View Code

      

    dfs 实现,只需要记录深度即可,不用记录节点

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def TreeDepth(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return 0
    11         self.depth = 0
    12         def helper(node, level):
    13             if not(node.left or node.right):
    14                 self.depth = max(self.depth, level)
    15                 return
    16             if node.left:
    17                 helper(node.left, level+1)
    18             if node.right:
    19                 helper(node.right, level+1)
    20                 
    21         helper(pRoot, 1)
    22         return self.depth
    View Code

      

    3. 二叉树的下一个节点

    给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

    解:

    几种可能的情况考虑一下即可

     1 # class TreeLinkNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 #         self.next = None
     7 class Solution:
     8     def GetNext(self, pNode):
     9         # write code here
    10         if not pNode:
    11             return 
    12         
    13         # 如果当前节点有右子树,中序遍历的下一个节点是其右子树的最左节点
    14         if pNode.right:
    15             pRight = pNode.right
    16             while pRight.left:
    17                 pRight = pRight.left
    18             return pRight
    19         
    20         # 如果当前节点没有右子树,但是当前节点是其父节点的左子节点,下一个节点是其父节点
    21         if pNode.next and pNode.next.left == pNode:
    22             return pNode.next
    23         
    24         # 如果当前节点没有右子树,但是是其父节点的右子节点,则一直向上遍历,找到是其父节点的左子结点的pNode
    25         # 当前节点的下一个节点就是pNode的父节点
    26         if pNode.next and pNode.next.right == pNode:
    27             while pNode.next and pNode != pNode.next.left:
    28                 pNode = pNode.next
    29             return pNode.next
    30         return 
    View Code

      

    4. 对称的二叉树

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

    解:

    递归实现,判断给定两个节点为根的子树是否镜像,首先根节点的值要相等,其次A的左子树和B的右子树、A的右子树和B的左子树要递归的进行判断

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def isSymmetrical(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return True
    11         return self.compare(pRoot.left, pRoot.right)
    12     
    13     def compare(self, p1, p2):
    14         if p1 == None :
    15             return p2 == None
    16         if p2 == None:
    17             return False
    18         if p1.val != p2.val:
    19             return False
    20         return self.compare(p1.left, p2.right) and self.compare(p1.right, p2.left)
    View Code

      

    dfs,用栈实现,成对取出成对插入,镜像:左左配右右,左右配右左

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def isSymmetrical(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return True
    11         stack = [pRoot.left, pRoot.right]
    12         
    13         while stack:
    14             right = stack.pop()  # 成对取出
    15             left = stack.pop()
    16             if left == None and right == None:
    17                 continue
    18             if  left == None or right == None:
    19                 return False
    20             if left.val != right.val:
    21                 return False
    22             
    23             # 成对插入
    24             stack.append(left.left)
    25             stack.append(right.right)
    26             stack.append(left.right)
    27             stack.append(right.left)
    28             
    29         return True
    View Code

    bfs,队列实现

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def isSymmetrical(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return True
    11         queue = [pRoot.left, pRoot.right]
    12         
    13         while queue:
    14             left = queue.pop(0)  # 成对取出
    15             right = queue.pop(0)
    16             if left == None and right == None:
    17                 continue
    18             if  left == None or right == None:
    19                 return False
    20             if left.val != right.val:
    21                 return False
    22             
    23             # 成对插入
    24             queue.append(left.left)
    25             queue.append(right.right)
    26             queue.append(left.right)
    27             queue.append(right.left)
    28             
    29         return True
    View Code

      

    5. 把二叉树打印成多行

    从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

    解:

    层次遍历,bfs

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     # 返回二维列表[[1,2],[4,5]]
     8     def Print(self, pRoot):
     9         # write code here
    10         if not pRoot:
    11             return []
    12         res = []
    13         queue = [pRoot]
    14         while queue:
    15             tmp = []
    16             for i in range(len(queue)):
    17                 node = queue.pop(0)
    18                 tmp.append(node.val)
    19                 if node.left:
    20                     queue.append(node.left)
    21                 if node.right:
    22                     queue.append(node.right)
    23             if tmp:
    24                 res.append(tmp)
    25         return res 
    View Code

      

    dfs

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     # 返回二维列表[[1,2],[4,5]]
     8     def Print(self, pRoot):
     9         # write code here
    10         if not pRoot:
    11             return []
    12         self.res = []
    13         
    14         def helper(node, level):
    15             if not node:
    16                 return 
    17             if level == len(self.res):
    18                 self.res.append([])
    19             self.res[level].append(node.val)
    20             if node.left:
    21                 helper(node.left, level + 1)
    22             if node.right:
    23                 helper(node.right, level + 1)
    24 
    25         helper(pRoot, 0)
    26         return self.res 
    View Code

      

    6. 按之字形顺序打印二叉树

    请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

    解:

    还是层次遍历,用一个 flag 控制每一层是正序还是逆序

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def Print(self, pRoot):
     8         # write code here
     9         if not pRoot:
    10             return []
    11         leftToRight = True
    12         queue = [pRoot]
    13         res = []
    14         while queue:
    15             tmp = []
    16             for i in range(len(queue)):
    17                 node = queue.pop(0)
    18                 tmp.append(node.val)
    19                 if node.left:
    20                     queue.append(node.left)
    21                 if node.right:
    22                     queue.append(node.right)
    23             if tmp:
    24                 if leftToRight:
    25                     res.append(tmp)
    26                 else:
    27                     res.append(tmp[::-1])
    28                 leftToRight = not leftToRight
    29         return res
    View Code

    7. 序列化二叉树

    请实现两个函数,分别用来序列化和反序列化二叉树
    二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
    二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
    解:
    这题的序列化就直接前序遍历实现即可,注意按要求用字符 # 和 !表示空节点和结束符。
    主要问题在反序列化上,还是按照根左右的顺序递归,用 flag 来控制递归过程中,反序列化的节点值在数组中的索引,flag从0开始,每次都+1,遇到‘#’说明是空节点,不需要构造node
     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     def __init__(self):
     8         self.flag = -1
     9     def Serialize(self, root):
    10         # write code here
    11         if not root:
    12             return '#!'
    13         return str(root.val)+'!'+self.Serialize(root.left)+self.Serialize(root.right)
    14         
    15     def Deserialize(self, s):
    16         # write code here
    17         self.flag += 1
    18         vals = s.split('!')
    19         if self.flag >= len(vals):
    20             return None
    21         root = None
    22         if vals[self.flag] != '#':
    23             root = TreeNode(int(vals[self.flag]))
    24             root.left = self.Deserialize(s)
    25             root.right = self.Deserialize(s)
    26         return root
    View Code

    8. 二叉搜索树的第k个节点

    给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8)    中,按结点数值大小顺序第三小结点的值为4。

    解:

    中序遍历即有序

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     # 返回对应节点TreeNode
     8     def KthNode(self, pRoot, k):
     9         # write code here
    10         if not pRoot:
    11             return None
    12         self.res = []
    13         self.midOrdTrav(pRoot)
    14         return self.res[k-1] if 0<k<=len(self.res) else None
    15     
    16     def midOrdTrav(self, root):
    17         if not root:
    18             return
    19         self.midOrdTrav(root.left)
    20         self.res.append(root)
    21         self.midOrdTrav(root.right)
    View Code

      

    中序遍历的时候维护一个计数器,到 k 个数了就返回

     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     # 返回对应节点TreeNode
     8     def KthNode(self, pRoot, k):
     9         # write code here
    10         if not pRoot:
    11             return None
    12         
    13         count = 0
    14         stack = []
    15         p = pRoot
    16         while p or stack:
    17             while p:
    18                 stack.append(p)
    19                 p = p.left
    20             if stack:
    21                 p = stack.pop()
    22                 count += 1
    23                 if count == k:
    24                     return p
    25                 p = p.right
    26         return None
    View Code

     

     
    9.数据流中的中位数
    如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
    解:
    维护两个堆,大顶堆用来存较小的数,从大到小排列;小顶堆用来存较大的数,从小到大排列。
    保证小顶堆中的元素都大于等于大顶堆中的元素(始终保证较大数的那一半多一个或者一样多,中位数始终在这一边),所以 insert 的时候先 push 进小顶堆(存较大的数),再把小顶堆中的最小值 pop 出来 push 到大顶堆(存较小的数)中。
    每次都检查,如果小顶堆的元素个数小于大顶堆的元素个数(较大的数比较小的数少了),就把大顶堆中的最大值 pop 出来 push 小顶堆。
    取中位数的时候,如果当前两个堆一样多,显然是取小顶堆和大顶堆根结点的平均值;如果当前小顶堆元素个数多一个,显然是取小顶堆的根节点
     1 import heapq
     2 class Solution:
     3     def __init__(self):
     4         self.small = []  # 小的数,大顶堆
     5         self.large = []  # 大的数,小顶堆
     6         
     7     def Insert(self, num):
     8         # write code here
     9         heapq.heappush(self.small, -heapq.heappushpop(self.large, num))
    10         if len(self.large) < len(self.small):
    11             heapq.heappush(self.large, -heapq.heappop(self.small))
    12             
    13     def GetMedian(self, default=None):
    14         # write code here
    15         if len(self.large) > len(self.small):
    16             return float(self.large[0])
    17         return (self.large[0] - self.small[0])/2.
    View Code

      

     
    10. 重建二叉树
    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
    解:
    其实就是一个递归的过程,每次找一下根节点在哪,进而定位好左右子树的切片,构建好了根节点之后再分别去构建左右子树
     1 # class TreeNode:
     2 #     def __init__(self, x):
     3 #         self.val = x
     4 #         self.left = None
     5 #         self.right = None
     6 class Solution:
     7     # 返回构造的TreeNode根节点
     8     def reConstructBinaryTree(self, pre, tin):
     9         # write code here
    10         if not pre or not tin:
    11             return None
    12         root = TreeNode(pre[0]) 
    13         index = self.Search(tin, root.val)  # tin.index(root.val)
    14         root.left = self.reConstructBinaryTree(pre[1:index+1], tin[:index])
    15         root.right = self.reConstructBinaryTree(pre[index+1:], tin[index+1:])
    16         return root
    17     
    18     def Search(self, nums, target):
    19         if not nums:
    20             return -1
    21         n = len(nums)
    22         for i in range(n):
    23             if nums[i] == target:
    24                 return i
    25         return -1
    View Code
  • 相关阅读:
    使用自定义注解动态绑定多实现类实例
    使用策略模式和工厂模式动态绑定多实现类实例
    使用责任链模式动态绑定多实现类实例
    使用模板方法模式动态绑定多实现类实例
    IDEA 调试Java代码的两个技巧
    Maven中dependencyManagement标签的正确使用方法
    Spring注解之获取自定义注解信息
    Spring注解之自定义注解入门
    Spring 动态绑定多实现类实例综述
    数据迁移测试
  • 原文地址:https://www.cnblogs.com/chaojunwang-ml/p/11492215.html
Copyright © 2011-2022 走看看