晚上没事,尝试解决一个小的算法问题。 我的算法比较弱,也没查什么参考资料,自己想的思路。肯定有更好的解法。
1. 找到1-10000范围内的素数, 得到一个有序数组A (时间复杂度为O(nlogn))
2. 对1-10000范围内的数进行遍历. 对每个数 i, 使用二分查找确定它在有序数组A中的"位置" pos (若存在,则为数组下标;若不存在,则为这个数插入该数组后仍能保证数组的大致位置) (时间复杂度为O(nlogn))
3. 从有序数组A的pos位置开始,令num = A[pos],二分查找确定 i - num是否也在这个数组A中。 若在, 则表示i可以用两个素数之和表示。否则, pos递减继续查找 (时间复杂度 O(n * n * logn) ??? )
第1步生成素数列表应该有更好的方法。 第3步感觉比较低效, 但实际运行时发现pos需要递减的情况比较少。也就是说,一个很大的偶数,基本上都会被分解成一个很大的素数和一个非常小的素数。下面是运行结果。
# encoding: utf-8 import math from timeit import Timer from functools import partial # 生成素数列表 # 版本一. 比较低效 def sushu(n): num = 2 alist = [2] for i in range(3, n + 1): istrue = True #for j in range(2, int(math.sqrt(i))): for j in range(2, i / 2 + 1): if i % j == 0: istrue = False break if istrue: alist.append(i) return alist # 生成素数列表 # 版本二 def sushu2(n): num = 2 alist = [2] for i in range(3, n + 1): istrue = True for j in range(2, int(math.sqrt(i)) + 1): #for j in range(2, i / 2): if i % j == 0: istrue = False break if istrue: alist.append(i) return alist # 生成素数列表 # 版本三 def sushu3(n): #num = 2 alist = [] for i in range(3, n + 1, 2): istrue = True for j in range(3, int(math.sqrt(i)) + 1): #for j in range(2, i / 2): if i % j == 0: istrue = False break if istrue: alist.append(i) return alist # 通过二分查找找到alist中最接近 n的数的位置 def bin_search(alist, n): low = 0 high = len(alist) while low < high: mid = low + (high - low) / 2 if n == alist[mid]: return mid elif n < alist[mid]: high = mid - 1 else: low = mid + 1 return low # 所有大于等于6的偶数都可以表示成两个(奇)素数之和。 def split(n): # 素数列表 alist = sushu3(n) alist_len = len(alist) for i in range(8, n + 1, 2): pos = bin_search(alist, i) #print pos # 修正pos if pos >= alist_len: pos = alist_len - 1 isok = 0 while pos > 0: isok = 1 #print pos >= alist_len j = i - alist[pos] # TODO in 是否低效 if j in alist: isok = 2 break pos -= 1 ''' if isok == 2: print '%d = %d + %d' %(i, alist[pos], i - alist[pos]) elif isok == 1: print '%d = 不能表示' % (i) else: print '%d = 运行异常' % (i) ''' # 所有大于等于6的偶数都可以表示成两个(奇)素数之和。 def split2(n): # 素数列表 alist = sushu3(n) alist_len = len(alist) for i in range(8, n + 1, 2): pos = bin_search(alist, i) #print pos # 修正pos if pos >= alist_len: pos = alist_len - 1 isok = 0 while pos > 0: isok = 1 #print pos >= alist_len j = i - alist[pos] if j == alist[bin_search(alist, j)]: isok = 2 break pos -= 1 ''' if isok == 2: print '%d = %d + %d' %(i, alist[pos], i - alist[pos]) elif isok == 1: print '%d = 不能表示' % (i) else: print '%d = 运行异常' % (i) ''' if __name__ == '__main__': #print sushu(100) if False: t = Timer(partial(sushu, 10000)) print t.timeit(10) t2 = Timer(partial(sushu2, 10000)) print t2.timeit(10) t3 = Timer(partial(sushu3, 10000)) print t3.timeit(10) if False: print sushu(100) print sushu2(100) print sushu3(100) if False: alist = sushu3(100) print alist for x in [96, 100, 110]: pos = bin_search(alist, x) print 'pos = ', pos #print alist[pos - 1], alist[pos], alist[pos + 1] if True: t = Timer(partial(split, 10000)) print t.timeit(10) t2 = Timer(partial(split2, 10000)) print t2.timeit(10)