剑指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

 

 

posted @ 2019-09-09 15:57  王朝君BITer  阅读(232)  评论(0编辑  收藏  举报