开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情
今天继续Codility的Lessons部分的第7个主题——Stacks and Queues
Codility - Lessons - Stacks and Queues
还是按先总结红色部分PDF,然后再完成蓝色的Tasks部分的节奏来~
PDF Reading Material
- 7.1-Stack: 讲了栈后进先出的概念,然后基于Python实现了个栈结构,构造了push(x)和pop()两个函数来实现入栈和出栈。
- 7.2-Queue: 讲了队列的概念,举了生活中排队的例子。然后基于Paython实现了个队列结构,构造了push(x),pop(),size()和empty()四个函数。
- 7.3-Exercises: 是提供了一个事件列表,里面包含排队人数增加(0)和队首排队人被服务并离开队列(1)两种事件,最终需要计算的,是初始状态队伍里至少需要已经有多少人了,才能确保发生列表事件的过程中,不会出现队伍已经没有人,却还要处理(1)事件的情况。提供的解法是使用一个size的变量来回放事件流
Tasks
- Brackets
算是比较经典的一题,判断输入的字符串S是否完美嵌套,完美嵌套的概念阐述起来非常繁琐,但直观理解其实就是看三种括号组成的S是否完全括号对称,或者说三种括号的左右侧,是否能够一组一组顺序从S中全部消除。
解题思路是利用栈的特性,将S中元素顺序压入栈内,如果是左括号就直接压入,如果是右括号,看和末尾元素能否组对,不能则返回0,能则弹栈。循环结束后再根据栈内是否还有剩余元素返回0/1:
def solution(S):
map_dict = {
'{': '}',
'[': ']',
'(': ')'
}
# 初始化stack,并循环S中元素顺序压栈
stack = []
for i,s in enumerate(S):
# 入栈元素是左括号
if s in map_dict:
stack.append(s)
# 入栈元素是右括号
else:
# 栈内无元素,或者最后一个元素不是一对
if len(stack)==0 or map_dict[stack[-1]]!=s:
return 0
else:
stack.pop()
# 压栈结束,判断是否栈内还有元素,有则返回1,没有则返回0
return 0 if len(stack)>0 else 1
- Fish
输入是A、B两个Array,A中每个元素代表对应位置处鱼的大小,B中每个元素表示对应位置处鱼游动的方向(只有0,1两个枚举值)。假设两只鱼所在位置分别为P、Q,则两只鱼会相遇当B[P]=1 and B[Q]=0(P<Q),而两只鱼相遇时只有size更大的鱼才能存活。最终需要返回一个数字,代表还有多少鱼会存活。
解题思路如下,对于N=len(A)条鱼,同时从A,B中第一个元素开始向后循环,第一只向下游的鱼之前的向上游的鱼,直接存活数+1。而从第一只向下游的鱼,用一个stack进行size记录,后续如果遇到向上的鱼,则调用while循环,持续将栈顶元素与向上游的鱼的size进行比对,直到判断上游的鱼被吃掉,或者吃掉所有下游鱼(后者情况存活鱼也要+1)。最终循环结束,stack中剩余的元素数就是向下游的存活鱼的个数,也要并入总存活数,并返回。代码如下,也相应进行了必要注释:
def solution(A, B):
down_stack = []
N = 0
for size,direct in zip(A,B):
if direct==0: # UP的鱼
if down_stack: # 有向downstream游的鱼
while down_stack and size>down_stack[-1]: # Up鱼的size大于Down鱼的Size
down_stack.pop()
if len(down_stack)==0: # Up鱼赢到最后,要+1
N += 1
else: # 没有向downstream游的鱼,+1
N += 1
else: # Down的鱼
down_stack.append(size)
N += len(down_stack)
return N
- Nesting
和第一题几乎一样的题干和解题思路,map_dict里只需要放()括号的映射,其他部分完全不用动。我没有太看出来和第一题的考察区别在哪里,有看出来的可以说下。
- StoneWall
本题输入是一个Array H,代表了一面墙的形状,其中每个元素,代表顺序的每个单位宽距离里墙有多高,有多少个元素则这个墙就有多宽。最后需要的输出,是这样一个形状的墙,最少需要用多少块矩形拼接得到。
照着题中给的样例图片,可以发现本质是统计一个水平线推移的问题,循环墙高Array,维护一个水平线的stack。每当出现更高墙高时,就加入stack中,并记录+1砖块数;每当出现更低墙高时,就顺序出栈水平线,直到栈顶的水平线小于等于当前墙高,接着继续分类讨论:如果是等于,就和之前这个水平线高的砖头是同一块,不需要+1砖头数;如果是小于,则当前墙高还是一块新砖头,还是要+1砖头数。最终循环结束,也就得到了总砖头数。
def solution(H):
N = 0
h_stack = [0] # 设定一个水平线0
for h in H:
if h > h_stack[-1]: # 1.比最后一次水平线高,作为新的水平线加入stack,并且砖头数+1
h_stack.append(h)
N += 1
elif h == h_stack[-1]: # 2.和最后一次水平线相等,保持不变
continue
elif h < h_stack[-1]:
# 3.比最后一次水平线低则持续出栈水平线,直到最后一次水平线<=此次水平线
# (由于设定过初始水平线0,所以一定可以跳出while循环)
while h < h_stack[-1]:
h_stack.pop()
# 跳出循环后,最后一次水平线小于本次水平线,则+1,等于的话就不用了
if h>h_stack[-1]:
h_stack.append(h)
N += 1
return N