LeetCode:150. 逆波兰表达式求值
https://leetcode.cn/problems/evaluate-reverse-polish-notation/
思路
如果遇到数字就压入栈中,如果遇到运算符就弹出栈顶两个元素进行运算(先弹出来的是运算符右边的数字,后弹出来的是运算符左边的数字),将结果压入栈中,最后栈中剩下的数字就是结果。
解答
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stk = []
for token in tokens:
if token == '+' or token == '-' or token == '*' or token == '/': # 如果是运算符就弹出栈顶两个元素进行运算
right_num = stk.pop()
left_num = stk.pop()
if token == '+':
result_num = left_num + right_num
elif token == '-':
result_num = left_num - right_num
elif token == '*':
result_num = left_num * right_num
else:
result_num = int(left_num / right_num)
stk.append(result_num)
else: # 如果是数字就压入
stk.append(int(token))
return stk[0]
LeetCode:239. 滑动窗口最大值
https://leetcode.cn/problems/sliding-window-maximum/
思路
暴力法
每次移动滑动窗口,就遍历窗口中的元素,找出最小值并记录。
时间复杂度为
O
(
n
×
k
)
O(n \times k)
O(n×k) ,但当
k
k
k 较大的时候,时间复杂度接近
O
(
n
2
)
O(n^2)
O(n2) 。
单调递减的双端队列
维护一个单调递减的双端队列,队列中存储元素下标,其对应值是可能成为最大值的元素。
遍历数组 nums 时:
- 移除队列中不在当前窗口内的下标(因此队列中记录的下标会更好进行判断);
- 移除队列中所有值小于等于当前元素的下标,保持单调递减;
- 将当前下标加入队列;
- 当窗口形成后,记录当前窗口的最大值。
例如,对于 nums = [1,3,-1,-3,5] ,k = 3 :
i = 0, num = 1,deque队列为空,直接压入对应的坐标0,得到deque = [0];i = 1, num = 3,deque = [0],因为 3 > 1 3 > 1 3>1 ,3更有可能成为最大值,弹出1对应的坐标0,压入3对应的坐标1,得到deque = [1];i = 2, num = -1,deque = [1],因为 − 1 < 3 -1 < 3 −1<3 ,直接舍弃,此时已经形成窗口(i == k - 1)且此后窗口一直存在直到遍历结束,将队列顶部元素对应的值记录到结果,得到results = [3];i = 3, num = -3,deque = [1],因为 − 3 < 3 -3 < 3 −3<3 ,直接舍弃,将队列顶部元素对应的值记录结果,得到results = [3, 3];i = 4, num = 5,deque = [1],因为 5 > 3 5 > 3 5>3 ,5更有可能成为最大值,弹出3对应的坐标1,压入5对应的坐标4,得到deque = [4],将队列顶部元素对应的值记录结果,得到results = [3, 3, 5];- 遍历结束,返回答案
results = [3, 3, 5]。
解答
from collections import deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
dq = deque() # 维护一个单调的双端队列,存储元素下标,维持下标对应的值单调递减
result = []
for i, num in enumerate(nums):
if dq and dq[0] < i - k + 1: # 移除队列中不在当前窗口内的下标
dq.popleft()
while dq and nums[dq[-1]] <= num: # 移除队列中所有值小于等于当前元素的下标,保持单调递减
dq.pop()
dq.append(i) # 将当前下标加入队列
if i >= k - 1: # 当窗口形成后,记录当前窗口的最大值
result.append(nums[dq[0]])
return result
时间复杂度:
O
(
n
)
O(n)
O(n) ,每个元素最多入队和出队一次。
空间复杂度:
O
(
k
)
O(k)
O(k) ,队列最多存储
k
k
k 个下标。
LeetCode:347. 前 K 个高频元素
https://leetcode.cn/problems/top-k-frequent-elements/description/
思路
python中的 heapq 模块可以提供小顶堆。
- 首先我们先统计每个数字出现的频次,得到
countMap。 - 维护一个长度为
k的小顶堆heapMin。遍历countMap,以count为排序标准,将元组(count, num)压入堆中。如果堆已满,则与堆顶元素进行比较:如果堆顶元素更小,则弹出堆顶元素,将元组(count, num)压入堆中;否则跳过。 - 最后留在堆中的就是频率最高的
k个数字。
解答
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
results = []
# 统计数字出现的频率
countMap = {}
for num in nums:
if num in countMap:
countMap[num] += 1
else:
countMap[num] = 1
# 构建一个小顶堆
heapMin = []
for num, count in countMap.items():
if len(heapMin) < k: # 如果堆内元素的数量小于k,则直接压入
heapq.heappush(heapMin, (count, num))
else: # 如果堆已满,则和堆顶元素进行比较
# 如果当前元素比堆顶元素大,则插入
if count > heapMin[0][0]:
heapq.heappop(heapMin)
heapq.heappush(heapMin, (count, num))
else: # 如果当前元素比堆顶元素小,则丢弃
continue
for count, num in heapMin:
results.append(num)
return results

2163

被折叠的 条评论
为什么被折叠?



