试题 历届真题 杨辉三角形(python)
题目描述
方案一(暴力求解:40分)
解题思路与代码
暴力求解,一行接一行的模拟并判断,直到找到对应的数并打印结果。
解题的代码如下:
n = int(input())
a1 = [1]
a2 = [1,1]
count = 0
flag = 1
while(flag):
# 先判断第一个
# print(a1)
for i in range(len(a1)):
count +=1
if a1[i]==n:
flag = 0
break
# 更新a1、a2
tmp = [1 for i in range(len(a2)+1)]
for i in range(1,len(a2)):
tmp[i] = a2[i-1]+a2[i]
a1 = a2
a2 = tmp
print(count)
提交结果
结果分析
可以看到只有四个点测试点通过,而其他的测试点全部超时。这时注意到N的取值范围达到了1010,所以很明显暴力求解无法满足时间要求。
方案二(组合数与二分查找:100分)
解题思路与代码
杨辉三角和组合数相关,可以表示为C(a,b)的形式,0<=b<=a。同时组合数的计算公式为:
-
开头的数为C(2x,x),x从1开始递增,例如2是C(2,1),6是C(4,2)......
-
每一斜行的递增规律是C(2x++,x),例如6是C(4,2),10是C(5,2)......
-
我们可以发现例如数字6有两个,而我们想输出的是位置最靠上的,则我们只需从下面斜排开始往上找N就可以保证N的位置一定是最小的。因为N最大不超过10e9,而C(32,16)已经大于10e9了,因此从x为16的斜排开始循环找N(采用二分法去找)
实现的代码如下:
global n
n = int(input())
# 计算阶乘
def C(b,a):
'''计算组合数C(b,a)'''
sum = 1
i = b
j =1
while(j<=a):
sum = sum*i/j
i -= 1
j += 1
# 如果比目标数大就直接返回
if sum>n:
return sum
return sum
def judge(x):
# 每一个斜行的开头都是C(2x,x),从右上到左下,2x逐渐加一
MIN = 2*x
# 这里令右边界为n,因为C(n,x)一定大于n
MAX = n
while(MAX>MIN):
mid = MIN+MAX>>1
if C(mid,x)>=n:
'''说明n在{MIN,mid}中'''
MAX = mid
else:
MIN = mid + 1
if (C(MAX,x)==n):
# print(MAX)
# print(x)
print(int((1+MAX)*MAX/2)+x+1)
return True
else:
return False
if n==1:
print(1)
else:
x = 16
while(x>=0):
if judge(x):
break
x -= 1
评测结果
结果分析与反思
主要是利用了二分查找的思路,同时也要注意查照时组合数不必全部计算出来,当大于我们要找的数时就可以直接返回。
同时,在python中,计算最终结果时,我一开始写的是int((1+MAX)*MAX/2+x+1),但是会出现结果太大的时候最后几位为0的情况,如下图所示:

这里暂时没有找到合理的解释,估计是何python的底层设计有关,改成int((1+MAX)*MAX/2)+x+1即可。
总结
这题好像是某一届的倒数第二题,属于较难的一道,大部分人可能都会直接使用暴力模拟来解题,这样虽然不能得到满分但是可以拿到一部分的分(同时速度快)。
在做题时需要关注题目给出的时间要求、空间要求、取值范围等,设计出最合适的算法。
总的来说,仍需要多加练习,在比赛时也要学会取舍(毕竟在这么短的时间内能全部满分做出来的需要运气与实力相兼并)。