150:逆波兰表达式求值
这个题是典型的用栈来去辅助求解的题目,很经典。本来我以为要构造两个栈,一个符号栈一个存储操作数的栈,但后来想想,构造一个存储操作数的栈就好了,符合直接拿出来就用了,还给他建个栈干嘛。。。整体思路就是,先遍历字符串,如果是遇到操作数,就直接进栈,如果是遇到符号,就取操作数栈中的前两个,做计算即可。但是这里要注意的是,是取出来的第一个数(操作符)第二个数,还是第二个数(操作符)第一个数。这个很重要,因为我写代码时候写的是第一个数(操作符)第二个数,所以就没通过,改完就好了。
具体代码如下:
def evalRPN(self,tokens):
stack=[]
for i in range(len(tokens)):
if tokens[i]=="+" or tokens[i]=="-" or tokens[i]=="*" or tokens[i]=="/":
num1=int(stack.pop())
num2=int(stack.pop())
if tokens[i]=="+":
num=num2+num1
elif tokens[i]=="-":
num=num2-num1
elif tokens[i]=="*":
num=num2*num1
elif tokens[i]=="/":
num=int(num2/num1)
stack.append(num)
else:
stack.append(int(tokens[i]))
return stack.pop()
347:前K个高频元素:
这个题看完就知道是map!用map去做统计,然后按照value排序取前K个高频的。思路很简单,但是为了降低一点复杂度,从快排的nlogn到nlogK,那还是得用堆排序来辅助求解,我们只需要维护前K个高频的就好了。这个题,主要是带我开辟了“heapq”的这片乐土,构造小顶堆的神器!如果碰到优先队列的题,就需要考虑用它了,本题的具体代码如下:
def topKFrequent(self,nums,k):
store=dict()
for i in range(len(nums)):
if nums[i] in store:
store[nums[i]]=store[nums[i]]+1
else:
store[nums[i]]=1
pri_que=[]
for key,value in store.items():
heapq.heappush(pri_que,(value,key))
if len(pri_que)>k:
heapq.heappop(pri_que)
result=[0]*k
for i in range(k-1,-1,-1):
result[i]=heapq.heappop(pri_que)[1]
return result
好吧,那就巩固一下使用优先队列,python的工具“heapq”的语法吧!
(1)简介:heapq 库是Python标准库之一,提供了构建小顶堆的方法和一些对小顶堆的基本操作方法(如入堆,出堆等),可以用于实现堆排序算法。
(2)使用heapq来创建堆。
# coding=utf-8
import heapq
array = [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]
heap = []
for num in array:
heapq.heappush(heap, num)
print("array:", array)
print("heap: ", heap)
heapq.heapify(array)
print("array:", array)
可以看到,heapq中创建堆的方法有两种。
heappush(heap, num),先创建一个空堆,然后将数据一个一个地添加到堆中。每添加一个数据后,heap都满足小顶堆的特性。
heapify(array),直接将数据列表调整成一个小顶堆(调整的原理参考上面堆排序的文章,heapq库已经实现了)。
结果:
array: [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]
heap: [5, 7, 21, 15, 10, 24, 27, 45, 17, 30, 36, 50]
array: [5, 7, 21, 10, 17, 24, 27, 45, 15, 30, 36, 50]
(3)使用heapq实现堆排序。
array = [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]
heap = []
for num in array:
heapq.heappush(heap, num)
print(heap[0])
# print(heapq.heappop(heap))
heap_sort = [heapq.heappop(heap) for _ in range(len(heap))]
print("heap sort result: ", heap_sort)
先将待排序列表中的数据添加到堆中,构造一个小顶堆,打印第一个数据,可以确认它是最小值。然后依次将堆顶的值取出,添加到一个新的列表中,直到堆中的数据取完,新列表就是排序后的列表。
heappop(heap),将堆顶的数据出堆,并将堆中剩余的数据构造成新的小顶堆。
结果:
5
heap sort result: [5, 7, 10, 15, 17, 21, 24, 27, 30, 36, 45, 50]
(4)获取堆中的最小值或最大值
array = [10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]
heapq.heapify(array)
print(heapq.nlargest(2, array))
print(heapq.nsmallest(3, array))
结果:
[50, 45]
[5, 7, 10]
nlargest(num, heap),从堆中取出num个数据,从最大的数据开始取,返回结果是一个列表(即使只取一个数据)。如果num大于等于堆中的数据数量,则从大到小取出堆中的所有数据,不会报错,相当于实现了降序排序。参考链接:Python heapq库的用法介绍
239:滑动窗口的最大值:
刷这道题是真不容易:
提交了好多次才通过:
不过时间用的比较长,那也不管了,起码做对了,吼吼!
这个题,看完视频后就自己摸索着写,觉得自己get到精髓了,但就是写不对,问题在哪里呢,主要是,需要判断,每进一个元素,需要将前面的元素(哪怕他是最大的)也要弹出,而且还需要保留次大值,以至于最大值因为k窗口大小的问题,弹出之后,次大值还能再补上!这一点,写了好久,从下午写道晚上,哎,觉得自己有点笨了。
具体代码如下:
def maxSlidingWindow(self,nums,k):
d=deque()
res=[]
max=-10000000
for i in range(k):
if i==0:
d.append(nums[i])
else:
while d and nums[i]>d[-1]:
d.pop()
d.append(nums[i])
res.append(d[0])
for i in range(k,len(nums)):
if d and nums[i-k]==d[0]:
d.popleft()
while d and nums[i]>d[-1]:
d.pop()
d.append(nums[i])
res.append(d[0])
return res
首先分为两个阶段进行求解res,第一个阶段是k以内的,再一个阶段是大于k的。还要注意是弹出左边的还是弹出右边的,左边的就是队头,右边的是队尾。通过维护一个自定义的单调队列来实现滑动窗口的效果,注意i-k的理解,i-k的意思是,检测队头的值是否等于“窗口外的第一个值(最接近窗口边缘的)”,就要删掉。这一点,很重要!
虽然这一个题是二刷了,但是做的还是这么磕磕绊绊,不过,我记得关于这个题的非常有趣的评论,哈哈!这瞬间让算法题目变得可爱起来啦!