一、题目:
有一个序列u,满足:
1. 第一个元素是1
2. 此后任意一个元素x,2x+1和3x+1也必定在u中
现给定整数n,求序列u中的第n个元素是什么?并输出该序列
规定:要注意算法的效率
二、分析
先找几个数计算一下:
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该最小值元素。下一次循环仍然取两个队首的最小值。
四、过程分析
五、实现代码
1 #-*- coding:utf-8 -*- 2 __author__ = 'Administrator' 3 4 from collections import deque 5 6 #返回列表中第n+1个元素 7 def deq_linear(Len): 8 count_n=1;h=1;d1=deque([]);d2=deque([]) 9 d_total=deque([1]) 10 while True: 11 if count_n>=Len: 12 return h,d_total 13 d1.append(2*h+1) 14 d2.append(3*h+1) 15 Min=min(d1[0],d2[0]) 16 if d1[0]==Min: 17 h=d1.popleft() 18 d_total.append(h) 19 else: 20 h=d2.popleft() 21 d_total.append(h) 22 count_n=count_n+1 23 24 if __name__=="__main__": 25 Len=10 26 h,li=deq_linear(Len) 27 print("长度为 %d 的序列:%s" %(Len,list(li))) 28 print("该序列第 %d 个元素为:%d" %(Len,h)) 29 #输出: 30 #长度为 10 的序列:[1, 3, 4, 7, 9, 10, 13, 15, 19, 21] 31 #该序列第 10 个元素为:21