【题目】
消息流吐出2,一种结构接收而不打印2,因为1还没出现。
消息流吐出1,一种结构接收1,并且打印:1,2。
消息流吐出4,一种结构接收而不打印4,因为3还没有出现。
消息流吐出5,一种结构接收而不打印5,因为3还没有出现。
消息流吐出7,一种结构接收而不打印7,因为3还没有出现。
消息流吐出3,一种结构接收3,并且打印:3,4,5。
消息流吐出9,一种结构接收而不打印9,因为6还没出现。
消息流吐出8,一种结构接收而不打印8,因为6还没出现。
消息流吐出6,一种结构接收6,并且打印:6,7,8,9。
已知一个消息流会不断地吐出整数1~N,但不一定按照顺序吐出。如果上次打印的数为i,那么当i+1出现是,请打印i+1及其之后接收过的并且连续的所有数,直到1~N全部接收并且打印完,请设计这种接收并打印的结构。
【要求】
消息流最终会吐出全部的1~N,当然最终也会打印完所有的1~N,要求接收和打印1~N的整个过程,时间复杂度为O(N)。
【基本思路】
对于接收的每一个数,如果能和之前接收的数连续起来,就归入之前的数据区间中,如果不能就单独成为一个区间。每一个区间使用单链表结构实现。
例如,接收2的时候,根据2生成一个单链表节点,因为没有其他元素,所以它单独成一个区间[2];接收1的时候,根据1生成一个节点,然后发现之前的区间[2]可以和1连续起来,所以将该节点归入区间[2],此时该区间更新为[1,2];接收4的时候,根据4生成一个节点,没有区间可以和它连续起来,所以它单独成一个区间[4];然后接收5,和4连续起来,[4]区间更新为[4,5];然后接收3,3可以和[1,2]连续起来,也可以和[4,5]连续起来,所有整体可以归入一个区间[1~5]。
为了加速合并的过程,使用两个哈希表headMap和tailMap,分别用来存放区间的开头节点和结尾节点。假设一个数n被接收,首先将n的节点添加到headMap和tailMap中。然后在headMap中寻找是否有n+1元素,如果有,说明以n+1开头的区间可以向左再添加一个数n,所以将区间扩充1位,将headMap中的n+1元素和tailMap中的n元素删除。然后在tailMap中寻找是否有n-1元素,如果有,说明以n-1结尾的区间可以向右再添加一个数n,所以将区间扩充1位,将tailMap中的n-1元素和headMap中的n元素删除。
什么时候打印呢?设置一个变量lastPrint,表示上一次打印的最后一个元素是什么,然后每次在headMap中寻找是否有lastPrint+1元素,如果有的话,将整个以lastPrint+1开头的区间的数都打印,然后更新lastPrint。
【代码实现】
#python3.5
class Node2:
def __init__(self, value):
self.value = value
self.next = None
class MessageBox:
def __init__(self):
self.headMap = {}
self.tailMap = {}
self.lastPrint = 0
def receive(self, value):
node = Node(value)
self.headMap[value] = node
self.tailMap[value] = node
if value + 1 in self.headMap:
node.next = self.headMap[value+1]
del self.headMap[value+1]
del self.tailMap[value]
if value - 1 in self.tailMap:
self.tailMap[value-1].next = node
del self.tailMap[value-1]
del self.headMap[value]
if self.lastPrint + 1 in self.headMap:
self.printValue()
def printValue(self):
head = self.headMap[self.lastPrint+1]
del self.headMap[self.lastPrint+1]
while head != None:
print(head.value, end=' ')
head = head.next
self.lastPrint += 1
del self.tailMap[self.lastPrint]