开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情
今天继续Codility的Lessons部分的第三个主题——Time Complexity,可以预感到Efficiency应该是这个部分题目的考察重点。
Codility - Lessons - Time Complexity
还是按先总结红色部分PDF,然后再完成蓝色的Tasks部分的节奏来~
PDF Reading Material
PDF大概可以分成下边这些部分:
- 前言:
- Comparison of different complexities:
- Time limit:
- Space Complexities:
- Exercise:
Task
Task1: FrogImp
题目很简单,输入为X,Y,D,其中X<=Y。需要返回一只青蛙从X开始,按D的步长进行跳跃,至少跳跃多少次之后可以到达大于等于Y。
第一次没有关注efficiency,也没怎么多想,直接写了一个初始化步数为0,之后while循环累加直到跳出返回的逻辑:
def solution(X, Y, D):
# Implement your solution here
jumps = 0
while X<Y:
X += D
jumps += 1
return jumps
结果Correctness倒是100%了,但是Peformance直接来了个0%:
重新修改了下计算方式,实际上可以直接不走时间复杂度为n的循环,而是直接将X和Y做差,与步长D进行计算得到结果:
def solution(X, Y, D):
# Implement your solution here
diff = Y-X
# 直接根据Y和X的差值与D相除后的整数和余数,确定需要jump的次数
a, b = diff//D, diff%D
return a + (b>0)
Task2: PermMissingElem
题目概括如下:输入为有N个元素的Array A,其中的元素为从1到N+1各不相同的整数,也就是说正好缺失了从1~N+1的N+1个整数中的一个,需要的输出即为缺失的这个数。
因为还是重点考察运行效率,所以选择循环两次的复杂度为n的解法:
- 构建一个全是0的list
- 然后循环A中元素一次,并用1中的list的各个index处的值进行计数。
- 再循环一次list中每个index的具体计数值,在第一个计数值为0处,直接跳出返回当时的index+1
def solution(A):
# 建立一个全是0的list,来记录每个自然数出现的次数
count_lst = [0] * (len(A)+1)
for a in A:
count_lst[a-1]+=1
# 再重新扫一遍count_lst,发现次数为0的,直接返回当时的index+1
for i,v in enumerate(count_lst):
if v==0:
return i + 1
Tasks3: TapeEquilibrium
概括题目如下:输入为Array A,可以任意选择Array中的某个index处截断,得到至少包含一个元素的前部分Array(称为A1),和至少包含一个元素的后部分Array(称为A2),需要的输出,是所有的截断可能下,最小的|sum(A1)-sum(A2)|
解题思路如下:Array A里的元素可能为正,可能为负。所以其实我们需要算出每一个截断位置的差值绝对值结果,才能最终确定最小差值绝对值是多少。
因为sum(A1)和sum(A2)两部分,其实对于不同位置的截断,是存在一个累加关系的,所以我们可以选择在A中从左到右+从右到左分别各扫一次,就可以依次算出每个截断位置处的sum(A1)和sum(A2)的值,当然空间上就需要构造一个长度为len(A)-1的数组来保存结果,我们称这个数组为diff_arr。
在来回扫完2遍,并分别把截断位置在不同index处的sum(A1)/sum(A2),加到/减到diff_arr的对应index处之后,我们便得到所有截断位置为index处时的sum(A1)-sum(A2)结果。此时再在diff_arr里从左到右扫一遍,就可以得到diff_arr中最小的绝对值了:
def solution(A):
# Implement your solution here
len_A = len(A)
diff_arr = [0] * (len_A-1)
# 从左到右计算当P在index处时的sum(A1), 并加在diff_arr[index]处
a1_sum = 0
for i, a in enumerate(A[:-1]):
a1_sum += a
diff_arr[i] += a1_sum
# 从右到左计算当P在index处时的sum(A2),并减在diff_arr[index处]
a2_sum = 0
for i, b in enumerate(A[::-1][:-1]):
a2_sum += b
diff_arr[len_A-2-i] -= a2_sum
# 再从左到右扫一遍算好的diff_arr,找到最低的abs值
min_abs_diff = abs(diff_arr[0])
for d in diff_arr[1:]:
if d == 0: # 最小的abs就是0,所以看到0返回就好
return 0
if d<0:
if -d<min_abs_diff:
min_abs_diff = -d
else: # d>0
if d<min_abs_diff:
min_abs_diff = d
return min_abs_diff