八 队列及BFS
Images Source: https://realpython.com/
来源
Datewhale33期__LeetCode 刷题 :
-
航路开辟者:杨世超
-
领航员:桐
-
航海士:杨世超、李彦鹏、叶志雄、赵子一
-
开源电子书
https://algo.itcharge.cn
1 队列
1.1 基础知识
- 与栈结构不同的是,队列的两端都"开口",要求数据只能从一端进,从另一端出
遵循 “先进先出” 的原则
-
实现
- 顺序队列:在顺序表的基础上实现的队列结构;
- 链队列:在链表的基础上实现的队列结构;
- 双端队列
双端队列又名double ended queue,简称deque,双端队列没有队列和栈这样的限制级,它允许两端进行入队和出队操作,也就是说元素可以从队头出队和入队,也可以从队尾出队和入队。
- 优先队列
优先队列是基于二叉堆实现, 优先指的是按某种优先级优先出列
- "优先级"可以是自己定义的一个元素属性
- 许多数据结构都可以用来实现优先队列,例如二叉堆、二叉平衡树等
- 时间复杂度
栈、队列
- Push (入栈、入队):O(1)
- Pop (出栈、出队):O(1)
- Access (访问栈顶、访问队头):O(1)
双端队列
- 队头、队尾的插入、删除、访问也都是O(1)
优先队列
- 访问最值:O(1)
- 插入:一般是◦ (logN),-些高级数据结构可以做到O(1)
- 取最值: O(logN)
-
python中
栈、队列、双端队列可以用 list 实现
优先队列可以用 heapq 库 -
队列的顺序存储实现
class Queue:
# 初始化空队列
def __init__(self, size=100):
self.size = size
self.queue = [None for _ in range(size)]
self.front = -1
self.rear = -1
# 判断队列是否为空
def is_empty(self):
return self.front == self.rear
# 判断队列是否已满
def is_full(self):
return self.rear + 1 == self.size
# 入队操作
def enqueue(self, value):
if self.is_full():
raise Exception('Queue is full')
else:
self.rear += 1
self.queue[self.rear] = value
# 出队操作
def dequeue(self):
if self.is_empty():
raise Exception('Queue is empty')
else:
self.front += 1
return self.queue[self.front]
# 获取队头元素
def front_value(self):
if self.is_empty():
raise Exception('Queue is empty')
else:
return self.queue[self.front + 1]
# 获取队尾元素
def rear_value(self):
if self.is_empty():
raise Exception('Queue is empty')
else:
return self.queue[self.rear]
1.2 相关题目
1.2.1 622 . 设计循环队列
class MyCircularQueue:
def __init__(self, k: int):
self.size = k + 1
self.queue = [None for _ in range(k + 1)]
self.front = 0
self.rear = 0
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
else:
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = value
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
else:
self.queue[self.front] = None
self.front = (self.front + 1) % self.size
return True
def Front(self) -> int:
if self.isEmpty():
return -1
else:
value = self.queue[(self.front + 1) % self.size]
return value
def Rear(self) -> int:
if self.isEmpty():
return -1
else:
value = self.queue[self.rear]
return value
def isEmpty(self) -> bool:
return self.front == self.rear
def isFull(self) -> bool:
return (self.rear + 1) % self.size == self.front
2 BFS
- 广度优先遍历
(1)从图中的某个初始点 v0 出发,首先访问初始点 v0。
(2)接着访问该顶点的所有未访问过的邻接点 v01 v02 v03 ……v0n。
(3)然后再选择 v01 v02 v03 ……v0n,访问它们的未被访问的邻接点,v010 v011 v012……v01n。
(4)直到所有与初始顶点 v 联通的顶点都被访问。
2.1 相关题目
2.1.1 463 . 岛屿的周长
- 思路: 利用BFS >>> 搜索出出界或
grid[nx][ny] == 0
>>> 周长加一
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
from collections import deque
m, n = len(grid), len(grid[0])
visvited = [[False] * n for _ in range(m)]
def bfs(i, j):
count = 0
q = deque()
q.append([i, j])
visvited[i][j] = True
dr = [(-1, 0), (0, 1), (0, -1), (1, 0)]
while q:
x, y = q.popleft()
for k in dr:
nx = x + k[0]
ny = y + k[1]
if nx < 0 or ny < 0 or nx >= m or ny >= n or not grid[nx][ny]:
count += 1
continue
if visvited[nx][ny]: continue
q.append([nx, ny])
visvited[nx][ny] = True
return count
for i in range(m):
for j in range(n):
if grid[i][j] == 1:
return bfs(i, j)
2.1.2 752 . 打开转盘锁
- 思路: 哈希 + BFS
class Solution:
def openLock(self, deadends: List[str], target: str) -> int:
dead = set(deadends)
q = collections.deque(["0000"])
visvited = {"0000": 0}
while q:
s = q.popleft()
if s in dead: continue
for i in range(4):
for j in (-1, 1):
change = (int(s[i]) + j) % 10
ns = s[:i] + str(change) + s[i + 1:]
if ns not in visvited:
visvited[ns] = visvited[s] + 1
q.append(ns)
if ns == target:
return visvited[ns]
return -1