高效的队列deque

今天这一题有点烧脑:

有一个序列u,满足:

1. 第一个元素是1

2. 此后任意一个元素x,2x+1和3x+1也必定在u中

现给定整数n,求序列u中的第n+1个元素是什么?

规定:要注意算法的效率

分析:

乍一想有点乱。先找几个数计算一下:

1

[1], 3, 4

1, [3], 4, 7, 10

1, 3, [4], 7, 9, 10, 13

其中这个9提醒我们,虽然单纯的2x+1或3x+1一定是递增的,但是前一个数的3x+1有可能大于后一个数的2x+1。因此,当要在序列u中取“下一个数”计算它的2x+1和3x+1时,如何选取?

笨办法是用一个列表保存序列u,每计算出一个新的2x+1和3x+1时,都遍历一遍当前的列表,然后找到适当的位置插入。这显然不符合本题对于效率的要求。

换一个角度思考:如果我们不是用一个列表,而是用两个列表表示序列u呢?这两个列表分别保存2x+1和3x+1的值。由于它们一定是递增的,新元素只要直接append在队尾即可。而“选取下一个数”的动作,相当于从两个列表的队首依次挑出较小的那一个。这道题目进一步变形为:两个已经各自按从小到大顺序排列的列表,如何合并为一个从小到大排序的列表?

实现要点:

1. 高效的队列:

用deque。这篇文章比较了deque, queue, 和list的性能。

2. 两个已经各自按从小到大顺序排列的列表,如何合并为一个从小到大排序的列表?

取两个队首的最小值,并pop该最小值元素。下一次循环仍然取两个队首的最小值。

代码参考

from collections import deque

def dbl_linear(n):
    h = 1; cnt = 0; q2, q3 = deque([]), deque([])
    while True:
        if (cnt >= n):
            return h
        q2.append(2 * h + 1)
        q3.append(3 * h + 1)
        h = min(q2[0], q3[0])
        if h == q2[0]: h = q2.popleft()
        if h == q3[0]: h = q3.popleft()
        cnt += 1

 

posted on 2017-05-30 16:16  jennyz_2017  阅读(231)  评论(0编辑  收藏  举报

导航