好久没写题解了,没办法,C站的题目更新的速度太慢了,重复考过去的老题已经不能再进步了。52期还混了个名次,总要写篇文章完成一下任务。而53期就惨了去了,三道选择题全蒙错了。
反正我个人觉得在现在C站的OJ环境里考选择题,真是出题人脑子被踢了。真要想拿满分太容易了:临时翻书这种笨方法就不提了,开赛后十分钟内出现的那么多0分选手还说明不了问题么?考完就能下载到正确答案,然后换个账户再进不就行了?对,我就是说给出题人听的,人家不是号称每期都复盘么?一个人复盘确实也有可能想不到这么多。:D
当然,你也可以鄙视我,就当我吃不到葡萄说葡萄酸好了。:D
闲言少叙,说回编程题。毕竟这种题才更适合问哥这种没学过计算机专业的人。(本来历史就差,计算机历史就更别提了。)
52期的4道题目还是都考过:
投篮:27期考过,最长递增子数组。
买苹果:30期考过,纯模拟,题解在此。当然背包也能做(有点杀鸡用牛刀的感觉)。
打家劫舍:29期考过,题解在此。动态规划入门题,或者说递推题(类似斐波那契)。
天然气订单:30期、48期考过两回,题解在此,并查集。应该还有别的解法,不过问哥太懒,没空去试了。
这里面只有投篮没写过题解,但实在是太简单了:最长递增子数组,从头到尾遍历一遍答案就出来了。
然而赛后发现,还是有童鞋没有拿到满分。猜测可能是由于读题时错误地理解“得分清零”,认为每次都是从0开始计算。但实际上,从给的示例中就可以看出来,当球没有投进时,得分虽然清零了,但给出的数组里并没有记0,而是从下一个投进的球开始计分。也就是说,即使有连续几个球都投不进,也是不会出现在这个计分数组里的。
这样一来,其实反而更简单了,因为不用去判断是否当前这个投球得分了。思路很简单:维护两个变量,一个是当前子数组的递增长度 temp,一个是最长的子数组长度,也就是答案 result。从头到尾遍历数组,如果当前数字(得分)比上一个数字大,则必然连续得分,temp 加一。反之,如果比上个数字小或相等,则必然这中间投篮失败,开始重新计分了,于是更新 result,再将 temp 重置为 1 (因为当前成功的投球也算一次)。循环结束时,还要记得再更新一次 result,因为有可能一直到最后都是递增的。
参考代码如下:
def solution(self, n, arr):
temp = result = 1
for i in range(1, n):
if arr[i] > arr[i-1]:
temp += 1
else:
result = max(temp, result)
temp = 1
return max(result, temp)
52期没什么可说的了,咱顺道说说53期。由于53期问哥选择题全错,砍掉30分,自然排不上名次了(而且不再是积分榜榜首了,终于治好了每期都参加的强迫症,哈哈),所以不会单独再写题解或文章。但是53期的两道编程题都是新题,虽然都是简单题。尤其是第2题等差数列,挺有意思的,有点脑筋急转弯的赶脚。问哥在此提供个思路,抛砖引玉,大家可以一起讨论。
这题乍看起来似乎有点不好下手,其实也非常简单。由等差数列的基本特性:相邻两个数字的差都相等(记为公差 d),可以轻松推导出:等差数列中任意两个数字的差都是这个公差 d 的倍数。 于是就可以得出结论:如果给出的数列可以组成等差数列(题目也是要求要尽可能组成等差数列)的话,其中已知的相邻数字的差的最大公约数 gcd,就是能构成等差数列的最大公差。
这里面有个特例,就是如果计算下来最大公约数是 0 的话,(0没有公约数,所以不能通过求最大公约数来得到 0,但是只要相邻数字的差是 0,就可以认为该数列最大公差是 0 了),如果首尾数字不相等的话,必然构成不了等差数列,答案是 NaN。而如果首尾数字相等,也不需要再添加任何数字了,因为这就是个由相同数字构成的“等差数列”,答案是 0。
得到最大公差后,要计算少了多少数字,就异常简单了:首尾相减,除去公差再加一,就得到这个数列的数字个数,减去给出数列的长度就是答案。
参考代码如下:
arr = sorted(map(int, input().split())) # 不确定给出的数列是否已经排好序,保险起见,先排序
d = arr[1] - arr[0]
if d > 0:
from math import gcd
for i in range(2, len(arr)):
q = arr[i] - arr[i-1]
if q == 0:
d = 0
break
d = gcd(q, d)
if d == 0:
if arr[0] == arr[-1]: print(0)
else: print("NaN")
else: print((arr[-1]-arr[0])//q - len(arr) + 1)
当然,如果只给出了一个数字,答案是0,也算特例,但这里就没有考到了。