61. 二叉树的序列化和反序列化
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
思路
利用先序遍历的思想来实现序列化和反序列化。序列化就是将树转化为字符串保存起来,相邻结点之间用,
分隔,空结点使用#
表示;反序列化就是根据字符串还原二叉树。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.index = -1
def Serialize(self, root):
# write code here
string = []
def preOrder(p):
if p == None:
string.append('#,')
else:
string.append(str(p.val) + ',')
preOrder(p.left)
preOrder(p.right)
preOrder(root)
string = ''.join(string)
return string
def Deserialize(self, s):
# write code here
self.index += 1
sp = s.split(',')
node = None
if sp[self.index] != '#':
node = TreeNode(int(sp[self.index]))
node.left = self.Deserialize(s)
node.right = self.Deserialize(s)
return node
简化了一点:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.index = -1
def Serialize(self, root):
# write code here
if root == None:
return '#,'
return str(root.val) + ',' + self.Serialize(root.left) + self.Serialize(root.right)
def Deserialize(self, s):
# write code here
self.index += 1
sp = s.split(',')
node = None
if sp[self.index] != '#':
node = TreeNode(int(sp[self.index]))
node.left = self.Deserialize(s)
node.right = self.Deserialize(s)
return node
62. 二叉搜索树的第 k k k个结点
题目描述
给定一棵二叉搜索树,请找出其中的第 k k k小的结点。例如, ( 5 , 3 , 7 , 2 , 4 , 6 , 8 ) (5,3,7,2,4,6,8) (5,3,7,2,4,6,8)中,按结点数值大小顺序第三小结点的值为4。
思路
思路一:中序遍历的递归算法
利用一个列表保存中序遍历的结果,时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( l o g h + n ) , h O(logh+n),h O(logh+n),h为树的深度.
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def KthNode(self, pRoot, k):
# write code here
res = []
def InOrder(root):
if not root:
return None
InOrder(root.left)
res.append(root)
InOrder(root.right)
InOrder(pRoot)
return res[k - 1] if 0 < k <= len(res) else None
思路二:中序遍历的非递归算法
利用中序遍历的非递归算法。时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( h ) , h O(h),h O(h),h为树的深度。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def KthNode(self, pRoot, k):
# write code here
count = 0
if k <= count:
return None
p, stack = pRoot, []
while p or len(stack) > 0:
while p:
stack.append(p)
p = p.left
tmp = stack.pop(-1)
count += 1
if count == k:
return tmp
p = tmp.right
return None
63. 数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路
思路一
每次插入时都把数据流调整为有序的,因此插入操作就相当于向有序数组中插入一个数,时间复杂度为
O
(
n
)
O(n)
O(n);取中位数时时间复杂度为
O
(
1
)
O(1)
O(1)。注意这里牛客网有个bug,GetMedian
函数必须多加一个任意参数才能通过。
class Solution:
def __init__(self):
self.data = []
def Insert(self, num):
if len(self.data) == 0:
self.data.append(num)
else:
i = 0
# 找到num应该被插入的位置
while i < len(self.data) and self.data[i] < num:
i += 1
# num大于现存所有值
if i == len(self.data):
self.data.append(num)
else:
self.data.append(0)
for j in range(len(self.data) - 2, i - 1, -1):
self.data[j + 1] = self.data[j]
self.data[i] = num
def GetMedian(self, damn):
length = len(self.data)
if length%2 == 1:
return self.data[length//2]
else:
return (self.data[length//2] + self.data[length//2-1])/2.0
思路二
该思路相当于把有序数组分成两个部分,左边一部分使用大根堆存储,右边一部分用小根堆存储。只要能保证两个堆大小相差不超过1,就很容易利用两个堆获得中位数,此时两个堆的堆顶值就为中间的值。具体操作如下。
插入操作:
首先判断大根堆是否为空:
如果为空则直接插入;
若不为空,则使用堆顶元素和待插入元素比较大小,若前者更大,则说明待插元素应该是属于左半部分的,即应该插入大根堆;若后者更大,则说明应该插入到右半部分,即小根堆。每次插入后都进行堆调整操作。
插入操作完毕后,需要调整两个堆长度差不超过1,如果长度差超过了1则将更长的堆的堆顶元素弹出并压入到较短的堆中。这个步骤主要是为了方便取中位数。
取中位数:
根据两个堆的长度差情况取出中位数。注意这里取堆顶元素直接使用heap[0]
即可,不能使用heappop
,这样会导致数据流序列变化。
除此之外,需要注意的是,python
的堆默认为小根堆,因此对于大根堆的插入,要把数字乘以
−
1
-1
−1,这样才能保证堆顶元素的相反数是最大值。
# -*- coding:utf-8 -*-
import heapq
class Solution:
def __init__(self):
self.small_heap = []
self.big_heap = []
def Insert(self, num):
# write code here
if len(self.big_heap) == 0:
self.big_heap.append(-1 * num)
elif num < self.big_heap[0] * -1:
heapq.heappush(self.big_heap, -1 * num)
else:
heapq.heappush(self.small_heap, num)
length_diff = len(self.big_heap) - len(self.small_heap)
if length_diff > 1:
tmp = heapq.heappop(self.big_heap)
heapq.heappush(self.small_heap, -1 * tmp)
elif length_diff < -1:
tmp = heapq.heappop(self.small_heap)
heapq.heappush(self.big_heap, -1 * tmp)
def GetMedian(self, m):
# write code here
length_diff = len(self.big_heap) - len(self.small_heap)
if length_diff > 0:
return -1 * self.big_heap[0]
elif length_diff == 0:
return (-1 * self.big_heap[0] + self.small_heap[0]) / 2.0
else:
return self.small_heap[0]