2.21 只考加法的面试题
算法要求输出64位正整数范围内不能由连续整数相加而成的整数,本文试图采用穷举法搜索出满足条件的整数
###代码1
lim = 800
def fixout(base,lim):#多少连续相加的数,第一个数字是多少
seq = []
for i in range(lim):
a = base * i + base * (base - 1) / 2
seq.append(a)
return seq
outseq = []
for i in range(lim):
outseq.append(i)
for j in range(len(outseq)):
print '**'
for jj in range(2,lim):#2-13个连续的数字相加
for jjj in range(len(fixout(jj,lim))):
aa = fixout(jj,lim)
if outseq[j] == aa[jjj]:
outseq[j] = 0
print outseq
代码1的代码段有4层嵌套,逻辑为构建一个递增列表和一个条件满足列表,逐一检查两个列表中是否有重合,重合则置0,复杂度为O(n^4),效率不高
###代码2
b = 0
def fixout(base,i):
return base * i + base * (base - 1) / 2
outseq = []
for i in range(520):
outseq.append(i)
for j in range(lim):
b += 1
print b
for jj in range(2,lim):
for jjj in range(1,lim):
if outseq[j] == fixout(jj,jjj):
outseq[j] = '-'
print outseq
#print range(1,a)
代码2简化了fixout函数,不再构建条件满足列表,直接运算比较,复杂度降低到O(n^3)
###代码3
b = 0#显示程序在运行
base = 2#从2个连续的数相加开始
lim = 8200#穷举的上限
outseq = []
for i in range(lim):
outseq.append(i)
a=len(outseq)
def isok(num,base,lim):
for i in range(lim):
if (base * i + base * (base - 1) / 2) > lim:
break
else:
if (base * i + base * (base - 1) / 2) == num:
return False
return True
def remove(seq,base):
for jj in range(len(seq)):
if not isok(seq[jj],base,lim):
seq[jj] = 0
for i in seq:
if i == 0:
seq.remove(i)
for base in range(2,lim):
b += 1
print b
remove(outseq,base)
print outseq
归纳发现两个连续的数相加产生的数最多,通过逐步删除原列表中不满足要求的数可以大幅降低后面循环的运算量,进而提高运算效率。
###算法结论
8197
8198
[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192]
验证了8200以内的所有数字,以上结果推测答案为2^n,数学证明后面补充。(可用反证法?)