542. 01 矩阵
多源bfs
超时的解法
class Solution(object):
def updateMatrix(self, mat):
"""
:type mat: List[List[int]]
:rtype: List[List[int]]
"""
def bfs(x,y):
heap = []
directions = [(-1,0),(1,0),(0,-1),(0,1)]
heapq.heappush(heap,(mat[x][y],(x,y)))
visited = set()
while heap:
d,(x,y) = heapq.heappop(heap)
if mat[x][y] == 0:
return d
if (x,y) in visited:
continue
visited.add((x,y))
for direction in directions:
new_x = x + direction[0]
new_y = y + direction[1]
if 0 <= new_x < m and 0 <= new_y < n and (new_x,new_y) not in visited:
heapq.heappush(heap,(d+mat[new_x][new_y],(new_x,new_y)))
return -1
m = len(mat)
n = len(mat[0])
res = [[0 for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
if mat[i][j] == 1:
d = bfs(i,j)
res[i][j] = d
return res
279 完全平方数
思路就是bfs,自己解法1的bfs超时,看官方答案解法2的bfs的,用Set来代替加入list再去重。
解法1
class Solution:
def numSquares(self, n: int) -> int:
if n == 1:
return 1
def sqr(n):
i =1
sqr_i = i**2
while i**2 <= n:
yield i**2
i+=1
squre_list = list(sqr(n))
mark_list =set()
queue = []
queue.append(n)
level = 0
while queue!= 0:
level+=1
size = len(queue)
while size != 0:
num = queue.pop(0)
for i in squre_list:
next_num = num -i
if next_num == 0:
return level
if next_num < 0:
break
if next_num not in mark_list:
mark_list.add(next_num )
queue.append(next_num )
size -= 1
def helper(n):
i=1
alist=[]
while i**2<n:
alist.append(i**2)
i=i+1
return alist
def build_model_v2(n):
alist=helper(n)
mask_list=[]
print(alist)
queen.append(n)
level=0
#队列先进先出
#在最开始把当前level的size保存下来,然后循环pop直到当前的size为0,就可以保证队列里每次都是cur_level的值
while len(queen)>0:
size=len(queen)
level=level+1
while size>=0:
num=queen.pop(0)
for i in range(len(alist)):
next_num=num-alist[i]
#下一层
if next_num=0:
return level
if next_num<0:
break
if next_num>0 and next_num not in mask_list:
queen.append(next_num)
mask_list.append(next_num)
size=size-1
解法2
Leetcode-279. 完全平方数,BFS建模深度分析 - 简书
和二叉树层次遍历一样
class Solution:
def numSquares(self, n):
# list of square numbers that are less than `n`
square_nums = [i * i for i in range(1, int(n**0.5)+1)]
level = 0
queue = {n}
while queue:
level += 1
#! Important: use set() instead of list() to eliminate the redundancy,
# which would even provide a 5-times speedup, 200ms vs. 1000ms.
next_queue = set()
# construct the queue for the next level
for remainder in queue:
for square_num in square_nums:
if remainder == square_num:
return level # find the node!
elif remainder < square_num:
break
else:
next_queue.add(remainder - square_num)
queue = next_queue
return level
class Solution(object):
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
square=[]
for i in range(1,n+1):
if i*i<=n:
square.append(i*i)
print(square)
#广度优先遍历,当本层出现n为0的时候,返回
from collections import deque
deque=deque()
deque.append((n,0))
visited_val=set()
visited_val.add(n)
while deque:
cur,d=deque.popleft()
if cur==0:
return d
next_node=[]
for val in square:
if val<=cur and cur-val not in visited_val:
deque.append((cur-val,d+1))
visited_val.add(cur-val)
127 单词接龙
bfs找最短路径
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: int
"""
from collections import deque
deq = deque()
deq.append((beginWord,1))
visited = set() #防止往回搜
visited.add(beginWord)
wordList_set = set(wordList) #转化为set查询快
chars=[]
#生成26个字母
for i in range(97,123):
chars.append(chr(i))
while deq:
cur,d = deq.popleft()
if cur == endWord:
return d
for i in range(len(cur)):
for j in range(len(chars)):
nexts = cur[:i] + chars[j] + cur[i+1:] #当前单词的下一层
if nexts in wordList_set and nexts not in visited:
visited.add(nexts)
deq.append((nexts,d+1))
return 0
注意:
在查找wordlist的时候,要把wordlist转化为set,不然会超时。
python在列表和集合中查找数据的区别(时间复杂度)_菜菜的博客-CSDN博客
单词接龙2
bfs找最短路+回溯
bfs得到word_next,word_level,dfs的循环条件
bfs+dfs
import string
import collections
class Solution(object):
def findLadders(self, beginWord, endWord, wordList):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: List[List[str]]
"""
# 思路:bfs建图,找到当前word的level;dfs深搜找到每个序列。
# bfs建图和127一样,额外需要把当前word的level保存下来。
lowercase = list(string.ascii_lowercase) # 26个小写字母列表
visited = [beginWord]
queen = [beginWord]
# key: word, value: a list of next words
word_next = collections.defaultdict(list)
# key: word, value: level
word_level = collections.defaultdict(int)
word_level[beginWord]=1
step = 1
while queen:
cur_size = len(queen)
for h in range(cur_size):
cur_word = queen.pop(0)
# 对cur word的每个字母遍历,找到符合条件的。
cur_word_list = list(cur_word)
for i in range(len(cur_word_list)):
cur_i = cur_word_list[i]
# 用26个字母替换
for j in lowercase:
if j != cur_i:
next_word = ''.join(cur_word_list[:i]) + j + ''.join(cur_word_list[i + 1:])
if next_word in wordList:
if next_word not in visited:
queen.append(next_word)
visited.append(next_word)
word_level[next_word]=step+1
if next_word==endWord:
word_next[cur_word].append(next_word)
break
word_next[cur_word].append(next_word)
step = step + 1
# dfs深搜求解;终止条件是cur word=end word;循环机制是对下层单词循环
def backtrack(word, path):
if word == endWord:
if path not in res:
res.append(path[:])
return
for w in word_next[word]:
# 这个单词在当前单词的下一层
if word_level[w] == word_level[word] + 1:
path.append(w)
backtrack(w, path)
path.pop()
res = []
backtrack(beginWord, [beginWord])
return res
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
from collections import deque
from collections import defaultdict
deq = deque()
deq.append((beginWord,1))
visited = set()
visited.add(beginWord)
wordList_set = set(wordList)
maps = defaultdict(list) #存储每个单词的下一层单词
maps_level = defaultdict(int) #存储这个单词位于哪层
chars=[]
for i in range(97,123):
chars.append(chr(i))
while deq:
cur,d = deq.popleft()
maps_level[cur] = d
if cur == endWord:
# # max_level = d #总共的层数
break #bfs终止
for i in range(len(cur)):
for j in range(len(chars)):
nexts = cur[:i] + chars[j] + cur[i+1:] #当前单词的下一层单词
if nexts in wordList_set:
if nexts not in maps[cur]:
maps[cur].append(nexts) #存储每个单词的下一层单词.要加在visit之前,不然被前一层的下一个相同节点只能存上一个
if nexts not in visited:
visited.add(nexts)
deq.append((nexts,d+1))
# print(maps)
#用回溯搜索路径,level表示层数
res=[]
path=[]
def dfs(cur_word,level):
if cur_word == endWord:
if path not in res:
res.append(path[:])
return
for i in range(len(maps[cur_word])):
tmp = maps[cur_word][i]
if maps_level[tmp] == level + 1:
path.append(tmp)
dfs(tmp,level+1)
path.pop()
path.append(beginWord)
dfs(beginWord,1)
return res
走迷宫
def hasPath(maze, start, destination):
m,n=len(maze),len(maze[0])
direcs=[(1,0),(0,-1), (0,1),(-1,0)]
start,destination=tuple(start),tuple(destination)
# 下面广度优先遍历
que=[start]
visited=set([start])
while que:
pos=que.pop(0)
for direc in direcs:
nex_pos=roll(pos, direc, maze)
if nex_pos==destination: return True
if nex_pos not in visited:
que.append(nex_pos)
visited.add(nex_pos)
return False
# 返回从pos=(x,y) 沿着direc=(dx, dy)方向 能到达的位置
def roll(pos, direc, maze):
m, n=len(maze),len(maze[0])
x, y=pos
dx, dy=direc
steps=0
# 只要不出界and不碰到墙 就严格一个方向滚
while 0<=x<m and 0<=y<n and maze[x][y]==0:
# print('maze[{}][{}]={}'.format(x,y,maze[x][y]))
x,y=x+dx, y+dy
# 因为出界/撞墙导致循环停止 因此后退一步
x, y=x-dx, y-dy
return (x,y)
作者:yuer-flyfly
链接:https://leetcode-cn.com/problems/the-maze/solution/mi-gong-tu-pu-tong-bfs-python-by-yuer-fl-0e6x/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
from collections import deque
class Solution(object):
def hasPath(self, maze, start, destination):
"""
:type maze: List[List[int]]
:type start: List[int]
:type destination: List[int]
:rtype: bool
"""
queue=deque()
queue.append((start[0],start[1]))
dires=[(-1,0),(1,0),(0,-1),(0,1)]
visited=[[False for _ in range(len(maze[0]))] for _ in range(len(maze))]
visited[start[0]][start[1]]=True
while queue:
x,y=queue.popleft()
#往四个方向走,直到撞到墙壁为止
for dire in dires:
r,c = x,y
#只要不出界and不碰到墙 就严格一个方向滚
while 0<=r<len(maze) and 0<=c<len(maze[0]) and maze[r][c]==0:
r=r+dire[0]
c=c+dire[1]
#退回一个是正常位置
r=r-dire[0]
c=c-dire[1]
if visited[r][c]==False:
queue.append((r,c))
visited[r][c]=True
if [r,c]==destination:
return True
return False
岛屿数量
深度优先搜索
class Solution(object):
def dfs(self,grid,i,j):
#不符合条件就返回
if not 0 <= i < len(grid) or not 0 <= j < len(grid[0]) or grid[i][j] == '0':
return
#遍历过这里就标记伟0
grid[i][j] = '0'
self.dfs(grid, i + 1, j)
self.dfs(grid, i, j + 1)
self.dfs(grid, i - 1, j)
self.dfs(grid, i, j - 1)
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
#dfs
count=0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
self.dfs(grid,i,j)
count=count+1
return count
广度优先搜索
同样地,我们也可以使用广度优先搜索代替深度优先搜索。
为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1
则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的
1都会被重新标记为0。直到队列为空,搜索结束。
最终岛屿的数量就是我们进行广度优先搜索的次数。
LeetCode200. 岛屿数量(python,bfs)_rosefun96的博客-CSDN博客
from collections import deque
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
#bfs
if len(grid) == 0:
return 0
queue = deque()
num_island = 0
dx = [1,0,-1,0]
dy = [0,1,0,-1]
visited = set()
queue2 = deque()
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == "1":
x,y = i,j
if (x, y) in visited:
continue
else:
visited.add((x,y))
num_island += 1
queue2.append((x,y))
while len(queue2) > 0:
x,y = queue2.popleft()
for k in range(4):
new_x = x+dx[k]
new_y = y+dy[k]
if new_x>=len(grid) or new_y>=len(grid[0]) or new_x<0 or new_y<0:
continue
if (new_x, new_y) not in visited:
visited.add((new_x,new_y))
if grid[new_x][new_y] == "1":
queue2.append((new_x,new_y))
return num_island
from collections import deque
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
res=0
queue=deque()
dires=[(-1,0),(1,0),(0,-1),(0,1)]
visited=[[False for _ in range(len(grid[0]))] for _ in range(len(grid))]
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j]=='1' and visited[i][j]==False:
res+=1
queue.append((i,j))
while queue:
x,y = queue.popleft()
#四个方向
for dire in dires:
r=x+dire[0]
c=y+dire[1]
if 0<=r<len(grid) and 0<=c<len(grid[0]) and grid[r][c]=='1' and visited[r][c]==False:
queue.append((r,c))
visited[r][c]=True
return res
并查集
岛屿数量2
并查集
class union_find(object):
def __init__(self, n):
self.root=[i for i in range(n)]
self.rank=[i for i in range(n)]
self.part=0
def find(self, x):
if x != self.root[x]:
self.root[x] = self.find(self.root[x])
return self.root[x]
def union(self, x,y):
rootX = self.find(x)
rootY = self.find(y)
if rootX!=rootY:
if self.rank[rootX] > self.rank[rootY]:
self.root[rootY] = rootX
elif self.rank[rootX] < self.rank[rootY]:
self.root[rootX] = rootY
else:
self.root[rootY] = rootX
self.rank[rootX] += 1
self.part=self.part-1
class Solution(object):
def numIslands2(self, m, n, positions):
"""
:type m: int
:type n: int
:type positions: List[List[int]]
:rtype: List[int]
"""
Row, Col = m, n
uf=union_find(m*n)
res = []
seen = set() #在并查中的,已经是陆地的位置
for r,c in positions:
ID = r * Col + c
if ID in seen: #样例中有重复
res.append(uf.part)
continue
seen.add(ID)
uf.part += 1 #先加上,再考虑合并
for nr, nc in ((r-1,c), (r+1,c), (r,c-1), (r,c+1)):
if 0 <= nr < Row and 0 <= nc < Col: #在版图内
id2 = nr * Col + nc
if id2 in seen: #已经是陆地了
uf.union(ID, id2)
res.append(uf.part)
return res
130 被围绕的区域
开始的做法:就像岛屿数量一样。但是这样有case判断不了,如下:
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
def dfs(i,j):
#返回条件
if not 0<=i<len(board)or not 0<j=<len(board[0]) or board[i][j]!="O":
return
#遍历过标记为m
board[i][j]="M"
dfs(i+1,j)
dfs(i-1,j)
dfs(i,j+1)
dfs(i,j-1)
for i in range(1,len(board)-1):
for j in range(1,len(board[0])-1):
if board[i][j]=='O':
dfs(i,j)
return board
正确的做法:
反向思维。从边界开始遍历,与边界的0联通的x,说明不能进行转化。其他的都是不与边界联通的,可以转化。
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
def dfs(i,j):
if not 0<=i<len(board) or not 0<=j<len(board[0]) or board[i][j]!="O":
return
board[i][j]='M'
dfs(i+1,j)
dfs(i-1,j)
dfs(i,j+1)
dfs(i,j-1)
m=len(board)
n=len(board[0])
#遍历左右边界
for i in range(m):
dfs(i,0)
dfs(i,n-1)
#遍历上下边界
for j in range(n):
dfs(0,j)
dfs(m-1,j)
#遍历数组
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j]=="O":
board[i][j]='X'
elif board[i][j]=="M":
board[i][j]='O'
286 墙与门
dfs超时
class Solution(object):
def wallsAndGates(self, rooms):
"""
:type rooms: List[List[int]]
:rtype: None Do not return anything, modify rooms in-place instead.
"""
def dfs(i,j,val):
#返回条件
#rooms[i][j]<val 说明,以前的值比较小的话,就不遍历了。
if not 0<=i<len(rooms) or not 0<=j<len(rooms[0]) or rooms[i][j]<val:
return
rooms[i][j]=val
dfs(i,j+1,val+1)
dfs(i,j-1,val+1)
dfs(i+1,j,val+1)
dfs(i-1,j,val+1)
for i in range(len(rooms)):
for j in range(len(rooms[0])):
if rooms[i][j]==0:
dfs(i,j,0)
return rooms
多源bfs
import collections
class Solution(object):
def wallsAndGates(self, rooms):
"""
:type rooms: List[List[int]]
:rtype: None Do not return anything, modify rooms in-place instead.
"""
queue = collections.deque()
for x in range(len(rooms)):
for y in range(len(rooms[0])):
if rooms[x][y] == 0:
queue.append(((x, y), 0)) ## 先加入队列,最后统一搜索
while queue:
(x, y), dis = queue.popleft()
for nx, ny in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
if 0 <= nx <= len(rooms)-1 and 0 <= ny <= len(rooms[0])-1:
if rooms[nx][ny] != 0 and rooms[nx][ny] != -1 and rooms[nx][ny] == 2147483647:
# 不越界且不是墙且没更新过
queue.append(((nx, ny), dis+1))
rooms[nx][ny] = dis + 1
return rooms
5973. 价格范围内最高排名的 K 样物品
分层bfs
我的做法:bfs板子题
class Solution(object):
def highestRankedKItems(self, grid, pricing, start, k):
"""
:type grid: List[List[int]]
:type pricing: List[int]
:type start: List[int]
:type k: int
:rtype: List[List[int]]
"""
# 广度优先搜索。
# 往上下左右四个方向走,如果遇到为1的格子,不能过去,其他可以过去。
# 求出来到符合价格的格子的最小步
import collections
queue = collections.deque()
queue.append(((start[0], start[1]), 0))
visited = []
visited.append((start[0], start[1]))
res = []
res2 = []
res3= []
#判断起点元素是否符合要求
nx=start[0]
ny=start[1]
if grid[nx][ny] >= pricing[0] and grid[nx][ny] <= pricing[1]:
res.append(((nx, ny), 0))
res2.append([nx, ny])
res3.append(0)
while queue:
(x, y), distance = queue.popleft()
for nx, ny in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
if 0 <= nx <= len(grid) - 1 and 0 <= ny <= len(grid[0]) - 1 and (nx, ny) not in visited:
if grid[nx][ny] != 0:
queue.append(((nx, ny), distance + 1))
visited.append((nx, ny))
print(queue)
# 判断是否在要找的价格范围内
if grid[nx][ny] >= pricing[0] and grid[nx][ny] <= pricing[1]:
#当距离相同时,判断其他三个条件
if res3 and distance+1 == res3[-1]:
#如果当前价格小,插到前面.不能保证比所有这个距离的都小。
if grid[nx][ny]<grid[res2[-1][0]][res2[-1][1]]:
insert_index=len(res)-1
res.insert(insert_index,((nx, ny), distance + 1))
res2.insert(insert_index,[nx, ny])
res3.insert(insert_index,distance + 1)
#价格相等的时候,行坐标:较小 行坐标的有更高优先级。
elif grid[nx][ny]==grid[res2[-1][0]][res2[-1][1]] and nx<res2[-1][0]:
insert_index = len(res) - 1
res.insert(insert_index, ((nx, ny), distance + 1))
res2.insert(insert_index, [nx, ny])
res3.insert(insert_index, distance + 1)
elif grid[nx][ny]==grid[res2[-1][0]][res2[-1][1]] and nx==res2[-1][0] and ny<res2[-1][1]:
insert_index = len(res) - 1
res.insert(insert_index, ((nx, ny), distance + 1))
res2.insert(insert_index, [nx, ny])
res3.insert(insert_index, distance + 1)
else:
res.append(((nx, ny), distance + 1))
res2.append([nx, ny])
res3.append(distance + 1)
else:
res.append(((nx, ny), distance + 1))
res2.append([nx, ny])
res3.append(distance+1)
print(res)
if len(res2) > k:
return res2[:k]
return res2
class Solution:
def highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], k: int) -> List[List[int]]:
# BFS
M = len(grid)
N = len(grid[0])
res = []
q = collections.deque([tuple(start)])
visited = set([tuple(start)])
while q and len(res) < k:
tmp = []
for _ in range(len(q)):
x, y = q.popleft()
if pricing[0] <= grid[x][y] <= pricing[1]:
tmp.append((x, y))
for nx, ny in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
if 0 <= nx < M and 0 <= ny < N and grid[nx][ny] != 0 and (nx, ny) not in visited:
q.append((nx, ny))
visited.add((nx, ny))
tmp.sort(key = lambda x: (grid[x[0]][x[1]], x[0], x[1]))
res += tmp
return res[:k]
作者:linzeyin
链接:https://leetcode-cn.com/problems/k-highest-ranked-items-within-a-price-range/solution/jian-dan-yi-dong-ji-mo-ban-hua-de-bfsxie-ssbo/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
此题细节较多:
1.如果起点满足价格条件,得把起点也加入到res中去排序
2.无论当前点的价格符合不符合要求,都要
deq.append(((new_x, new_y), d + 1))
3.最后返回的时候,要判断一下res和k的关系
class Solution:
def highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], k: int) -> List[List[int]]:
# 求最短路径,并按照价格和坐标排序
from collections import deque
deq = deque()
deq.append(((start[0], start[1]), 0))
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
visited = set()
visited.add((start[0], start[1]))
res = []
if grid[start[0]][start[1]]>= pricing[0] and grid[start[0]][start[1]]<= pricing[1]:
res.append([0, grid[start[0]][start[1]], start[0], start[1]])
while deq:
(cur_x, cur_y), d = deq.popleft()
for direction in directions:
new_x = cur_x + direction[0]
new_y = cur_y + direction[1]
if new_x >= 0 and new_x < len(grid) and new_y >= 0 and new_y < len(grid[0]) and (
new_x, new_y) not in visited and grid[new_x][new_y]!=0:
if grid[new_x][new_y] >= pricing[0] and grid[new_x][new_y] <= pricing[1]:
res.append([d+1,grid[new_x][new_y], new_x, new_y])
deq.append(((new_x, new_y), d + 1))
visited.add((new_x, new_y))
res.sort(key=lambda k: (k[0], k[1], k[2]), reverse=False)
res2=[]
if len(res)>=k:
for i in range(k):
res2.append([res[i][2],res[i][3]])
else:
for i in range(len(res)):
res2.append([res[i][2],res[i][3]])
return res2
2045. 到达目的地的第二短时间
这个题的难点不在于bfs,而在于如何求次短路径。与平时常见的bfs的区别是,没有visited。
另外一个是如何计算红绿灯时间。通过除法和余数的形式
建图+次短路
class Solution:
def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
#bfs加入队列,求路径
#先把图转化成邻接矩阵
graph = [[] for _ in range(n + 1)]
for e in edges:
x, y = e[0], e[1]
graph[x].append(y)
graph[y].append(x)
from collections import deque
deque=deque()
#起点
deque.append(edges[0][0])
while deque:
#记录层数。因为要计算什么时候出红灯
tmp=[]
for i in range(len(deque)):
cur_node=deque.popleft()
#与他相临的的节点
next_nodes=graph[cur_node]
for next_node in next_nodes:
deque.append(next_node)
class Solution:
def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
#bfs加入队列,求路径
#先把图转化成邻接矩阵
graph = [[] for _ in range(n + 1)]
for e in edges:
x, y = e[0], e[1]
graph[x].append(y)
graph[y].append(x)
#存储起点到其他节点的最短路径和次短路径
dist=[[-1]*2 for _ in range(n+1)]
from collections import deque
deque=deque()
#起点。图中有 n 个节点,从 1 到 n 编号
#deque记录起点到其他点的距离
deque.append((1,0))
while deque:
cur_node,d = deque.popleft()
#最短路径
if dist[cur_node][0]==-1:
dist[cur_node][0]=d
#次短路径
elif dist[cur_node][1]==-1 and dist[cur_node][0]<d:
# elif dist[cur_node][1]==-1:
dist[cur_node][1]=d
else:
continue
next_nodes=graph[cur_node]
for next_node in next_nodes:
deque.append((next_node,d+1))
second_dist=dist[-1][1]
res=0
# 计算通过红绿灯的时间
for i in range(second_dist):
#如果红绿灯切换次数为奇数,则现在是红灯
if res//change % 2 ==1:
#等到绿灯再出发(红灯剩余时间)
res+=change-res%change
res+=time
return res
# 计算通过红绿灯的时间
# for i in range(second_dist):
# if (res//change)&1:
# res=res//change*change+change
# res+=time
# return res
2039. 网络空闲的时刻
建图+最短路
class Solution:
def networkBecomesIdle(self, edges: List[List[int]], patience: List[int]) -> int:
from collections import deque
deq=deque()
#先找数据服务器到主服务器的路径,得到数据服务器发出消息到主服务器的时间
#从路径最小的开始,计算它发出数据到变空闲的时间,取最大值
#如何求每个节点到原点的最小路径呢?队列的方法
#建图,然后求最短路
n=len(patience)
distance=[-1 for _ in range(n)]
graph=[[] for _ in range(n)]
for i in range(len(edges)):
graph[edges[i][0]].append(edges[i][1])
graph[edges[i][1]].append(edges[i][0])
#节点0,到节点0的距离是0
deq.append((0,0))
while deq:
cur_node,d=deq.popleft()
next_nodes=graph[cur_node]
for next_node in next_nodes:
if distance[next_node]==-1:
distance[next_node]=d+1
deq.append((next_node,d+1))
res=0
#求每个节点,变为空闲的时间.
#注意:在第一个收到0节点的回复之后,就不会再发送消息了
for i in range(1,n):
first_receive_time=distance[i]*2
#在first_receive_time之前多发送了多少条
m=(first_receive_time-1)//patience[i]
#最后一条距离0时间多久
other_time=patience[i]*m
res=max(res,first_receive_time+other_time+1)
return res
1765. 地图中的最高点
我的解法:超时了。看了答案之后,是先把水域全都加到队列,然后在搜。
class Solution(object):
def highestPeak(self, isWater):
"""
:type isWater: List[List[int]]
:rtype: List[List[int]]
"""
# [[0,0,1],
# [1,1,0],
# [0,1,0]]
#思路:新建一个高度矩阵,从水域开始,值为1的,设置为0
#然后遍历上下左右四个方向。每次加1。
#当遍历到一个新的水域时,如果他的上下左右方向有值,取最小值。比如如果以前时2,但是这个新水域算的是1,就取1。
m=len(isWater)
n=len(isWater[0])
from collections import deque
deque=deque()
height=[[-1 for _ in range(n)] for _ in range(m)]
directs=[(-1,0),(1,0),(0,-1),(0,1)]
for i in range(m):
for j in range(n):
if isWater[i][j]==1:
deque.append([(i,j),0])
visited=[[False for _ in range(n)] for _ in range(m)]
visited[i][j]=True
while deque:
(x,y),d=deque.popleft()
if height[x][y]!=-1 and height[x][y]>d:
height[x][y]=d
if height[x][y]==-1:
height[x][y]=d
#上下左右四个方向
for (dx,dy) in directs:
if x+dx>=0 and x+dx<m and y+dy>=0 and y+dy<n and visited[x+dx][y+dy]==False and isWater[x+dx][y+dy]!=1:
deque.append([(x+dx,y+dy),d+1])
visited[x+dx][y+dy]=True
return height
class Solution(object):
def highestPeak(self, isWater):
"""
:type isWater: List[List[int]]
:rtype: List[List[int]]
"""
# [[0,0,1],
# [1,1,0],
# [0,1,0]]
#思路:新建一个高度矩阵,从水域开始,值为1的,设置为0
#然后遍历上下左右四个方向。每次加1。
#当遍历到一个新的水域时,如果他的上下左右方向有值,取最小值。比如如果以前时2,但是这个新水域算的是1,就取1。
m=len(isWater)
n=len(isWater[0])
from collections import deque
deque=deque()
height=[[-1 for _ in range(n)] for _ in range(m)]
directs=[(-1,0),(1,0),(0,-1),(0,1)]
visited=[[False for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
if isWater[i][j]==1:
deque.append([(i,j),0])
visited[i][j]=True
while deque:
(x,y),d=deque.popleft()
if height[x][y]!=-1 and height[x][y]>d:
height[x][y]=d
if height[x][y]==-1:
height[x][y]=d
#上下左右四个方向
for (dx,dy) in directs:
if x+dx>=0 and x+dx<m and y+dy>=0 and y+dy<n and visited[x+dx][y+dy]==False and isWater[x+dx][y+dy]!=1:
deque.append([(x+dx,y+dy),d+1])
visited[x+dx][y+dy]=True
return height
剑指offer112 最长递增路径
图的遍历,深度优先
class Solution:
# 图的遍历,深度优先遍历。
# 从较小的数指向较大的数,有向无环图
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
if m == 0 or n == 0:
return 0
lengths = [[0] * n for _ in range(m)]
longest = 0
for i in range(m):
for j in range(n):
length = self.dfs(matrix, lengths, i, j)
longest = max(longest, length)
return longest
def dfs(self, matrix, lengths, i, j):
if lengths[i][j] != 0: # 如果值不为0,说明之前已经计算过以坐标(i, j)为起点的最长递增路径的长度,矩阵lengths起到缓存的作用,确保以任意坐标为起点的最长递增路径的长度只需计算一次。
return lengths[i][j]
rows, cols = len(matrix), len(matrix[0])
dirs = [(-1, 0), (0, -1), (1, 0), (0, 1)]
length = 1
for dir in dirs:
r = i + dir[0]
c = j + dir[1]
if r >= 0 and r < rows and c >= 0 and c < cols and matrix[r][c] > matrix[i][j]:
path = self.dfs(matrix, lengths, r, c)
length = max(path + 1, length)
lengths[i][j] = length
return length
作者:you-lan-10
链接:https://leetcode-cn.com/problems/fpTFWP/solution/jian-zhi-offer112-zui-chang-di-zeng-lu-j-j775/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
def dfs(i,j):
if lengths[i][j]>0:
return lengths[i][j]
length=1
#上下左右移动
dirs=[(-1,0),(1,0),(0,-1),(0,1)]
for cur_dir in dirs:
r=i+cur_dir[0]
c=j+cur_dir[1]
if 0<=r<len(matrix) and 0<=c<len(matrix[0]) and matrix[r][c]>matrix[i][j]:
path=dfs(r,c)
#保证取到的是循环中最大的那个path
length=max(path+1,length)
# length=path+1
lengths[i][j]=length
return length
#遍历,找以每个元素为起点的最长递增路径
res=1
lengths=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
for i in range(len(matrix)):
for j in range(len(matrix[0])):
cur=dfs(i,j)
res=max(cur,res)
return res
[[7,7,5],
[2,4,6],
[8,2,0]]
5544 执行操作后字典序最小的字符串
这是一个周赛题,当时没做出来,后来看题解,居然是dfs or bfs 遍历。。。
class Solution(object):
def lunzhuan(self,s,b):
alist=list(s)
s1=alist[-b:]
s2=alist[:len(s)-b]
return ''.join(str(i) for i in s1+s2)
def leijia(self,s,a):
alist=list(s)
for i in range(len(s)):
if i%2 !=0:
alist[i]=int(alist[i])+a
if alist[i]>=9:
alist[i]=alist[i]%10
return ''.join(str(i) for i in alist)
def findLexSmallestString(self, s, a, b):
ans = '9' * 100
queue = [s]
visited = set()
visited.add(s)
while queue:
len_ = len(queue)
while len_:
p = queue.pop(0)
ans = min(ans,p)
m,e = self.leijia(p,a),self.lunzhuan(p,b)
if m not in visited:
queue.append(m)
visited.add(m)
if e not in visited:
queue.append(e)
visited.add(e)
len_ -= 1
return ans
5548. 最小体力消耗路径
回溯
class Solution(object):
def __init__(self):
self.res = []
self.min_v = float("inf")
def chazhi(self,num):
max_v=0
for i in range(len(num)-1):
diff= abs(num[i+1]-num[i])
if diff>max_v:
max_v=diff
return max_v
def minimumEffortPath(self, heights):
"""
:type heights: List[List[int]]
:rtype: int
"""
rows=len(heights)
cols=len(heights[0])
path=[]
boolmatrix = [0] * (rows * cols)
self.helper(heights, rows, cols, 0, 0, path,boolmatrix)
return self.min_v
def helper(self, matrix, rows, cols, row, col, path,boolmatrix):
path.append(matrix[row][col])
boolmatrix[row*cols + col] = True
if row==rows-1 and col==cols-1:
cur_v = self.chazhi(path)
if cur_v<self.min_v:
self.min_v=cur_v
if self.min_v == 0:
return
return
if row+1<rows and col<cols and not boolmatrix[(row+1)*cols + col]:
self.helper(matrix, rows, cols, row+1, col, path,boolmatrix)
boolmatrix[(row+1)*cols + col] = False
path.pop()
if row-1>=0 and col<cols and not boolmatrix[(row-1)*cols + col]:
self.helper(matrix, rows, cols, row-1, col, path,boolmatrix)
path.pop()
boolmatrix[(row-1)*cols + col] = False
if row<rows and col+1<cols and not boolmatrix[row*cols + col+1]:
self.helper(matrix, rows, cols, row, col+1, path,boolmatrix)
path.pop()
boolmatrix[row*cols + col+1]= False
if row<rows and col-1>=0 and not boolmatrix[row*cols + col-1]:
self.helper(matrix, rows, cols, row, col-1, path,boolmatrix)
path.pop()
boolmatrix[row*cols + col-1] = False
bfs
class Solution:
def minimumEffortPath(self, heights: List[List[int]]) -> int:
row=len(heights)
col=len(heights[0])
#distance 表示当前节点与 (0,0) 点最小体力消耗。
distance=[[float('inf')]* col for _ in range(row)]
distance[0][0]=0
def bsf(queue):
dd = [[0, 1], [1, 0], [0, -1], [-1, 0]]
while queue:
x, y,old_x,old_y = queue.pop(0)
for i in dd:
new_x = x + i[0]
new_y = y + i[1]
#判断新访问节点合法的条件,在棋盘内,并且不能重复访问来时的节点
if 0 <= new_x < row and 0 <= new_y < col and (new_x,new_y)!=(old_x,old_y ):
if distance[new_x][new_y]>max(distance[x][y],abs(heights[new_x][new_y] - heights[x][y])):
#如果 (new_x,new_y) 点最小体力消耗改变,将此点加入广度搜索序列
distance[new_x][new_y]=max(distance[x][y],abs(heights[new_x][new_y] - heights[x][y]))
queue.append((new_x,new_y,x,y))
bsf([(0,0,-1,-1)])
return distance[-1][-1]
作者:chang-qing-zi
链接:https://leetcode-cn.com/problems/path-with-minimum-effort/solution/python-yan-du-you-xian-sou-suo-by-chang-qing-zi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
并查集模版
class Solution(object):
def minimumEffortPath(self, heights):
"""
:type heights: List[List[int]]
:rtype: int
"""
M = len(heights)
N = len(heights[0])
dsu = DSU()
edges = []
for i in range(M):
for j in range(N):
pos = i * N + j
if i < M - 1:
#下边
edges.append([abs(heights[i + 1][j] - heights[i][j]), pos, pos + N])
if j < N - 1:
#右边
edges.append([abs(heights[i][j + 1] - heights[i][j]), pos, pos + 1])
edges.sort()
for edge in edges:
dsu.union(edge[1], edge[2])
if dsu.connected(0, M * N - 1):
return edge[0]
return 0
class DSU:
def __init__(self):
self.par = range(10001)
def find(self, x):
if x != self.par[x]:
self.par[x] = self.find(self.par[x])
return self.par[x]
def union(self, x, y):
self.par[self.find(x)] = self.find(y)
def connected(self, x, y):
return self.find(x) == self.find(y)
力扣
407 接雨水2
核心思想是:当确定一个外圈的最小值之后,以他为起点往四个方向遍历,如果遍历到的点小于他,那么肯定可以接满以他为高度的雨水。这里类似脑筋急转弯要想明白。
最小堆+广搜
(最小堆+广搜,其实就是迪杰斯特拉算法求最短路径问题)
class Solution:
def trapRainWater(self, heightMap: List[List[int]]) -> int:
if len(heightMap) <= 2 or len(heightMap[0]) <= 2:
return 0
m, n = len(heightMap), len(heightMap[0])
visited = [[0 for _ in range(n)] for _ in range(m)]
pq = []
for i in range(m):
for j in range(n):
if i == 0 or i == m - 1 or j == 0 or j == n - 1:
visited[i][j] = 1
heapq.heappush(pq, (heightMap[i][j], (i, j)))
res = 0
dirs = [(-1, 0), (1, 0), (0, 1), (0, -1)]
while pq:
height, (position_x, position_y) = heapq.heappop(pq)
for dir in dirs:
nx, ny = position_x + dir[0], position_y + dir[1]
if nx >= 0 and nx < m and ny >= 0 and ny < n and visited[nx][ny] == 0:
if height > heightMap[nx][ny]:
res += height - heightMap[nx][ny]
visited[nx][ny] = 1
heapq.heappush(pq, (max(height, heightMap[nx][ny]), (nx, ny)))
# for k in range(4):
# nx, ny = position // n + dirs[k], position % n + dirs[k + 1]
# new_x,new_y = position_x + dirs[k]
# if nx >= 0 and nx < m and ny >= 0 and ny < n and visited[nx][ny] == 0:
# if height > heightMap[nx][ny]:
# res += height - heightMap[nx][ny]
# visited[nx][ny] = 1
# heapq.heappush(pq, (max(height, heightMap[nx][ny]), nx * n + ny))
return res
class Solution:
def trapRainWater(self, heightMap: List[List[int]]) -> int:
m, n = len(heightMap), len(heightMap[0])
maxHeight = max(max(row) for row in heightMap)
water = [[maxHeight for _ in range(n)] for _ in range(m)]
dirs = [-1, 0, 1, 0, -1]
qu = []
for i in range(m):
for j in range(n):
if i == 0 or i == m - 1 or j == 0 or j == n - 1:
if water[i][j] > heightMap[i][j]:
water[i][j] = heightMap[i][j]
qu.append([i, j])
while len(qu) > 0:
[x, y] = qu.pop(0)
for i in range(4):
nx, ny = x + dirs[i], y + dirs[i + 1]
if nx < 0 or nx >= m or ny < 0 or ny >= n:
continue
if water[x][y] < water[nx][ny] and water[nx][ny] > heightMap[nx][ny]:
water[nx][ny] = max(water[x][y], heightMap[nx][ny])
qu.append([nx, ny])
ans = 0
for i in range(m):
for j in range(n):
ans = ans + water[i][j] - heightMap[i][j]
return ans
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/trapping-rain-water-ii/solution/jie-yu-shui-ii-by-leetcode-solution-vlj3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
priority_queue<pair<int, pair<int, int> >, vector<pair<int, pair<int, int> > >, greater<pair<int, pair<int, int> > > > pq;
bool vis[201][201];
int dirx[4] = {0, 0, 1, -1};
int diry[4] = {1, -1, 0, 0};
int trapRainWater(vector<vector<int>>& heightMap) {
int n = heightMap.size(), m = heightMap[0].size(), ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (i == 0 || i == n - 1 || j == 0 || j == m - 1) {
pq.push(make_pair(heightMap[i][j], make_pair(i, j)));
vis[i][j] = true;
}
}
}
while (!pq.empty()) {
int h = pq.top().first, x = pq.top().second.first, y = pq.top().second.second;
pq.pop();
for (int i = 0; i < 4; i++) {
int nx = dirx[i] + x, ny = diry[i] + y;
if (nx >= 0 && nx < n && ny >= 0 && ny < m && (!vis[nx][ny])) {
if (heightMap[nx][ny] < h) {
ans += h - heightMap[nx][ny];
}
vis[nx][ny] = 1;
pq.push(make_pair(max(heightMap[nx][ny], h), make_pair(nx, ny)));
}
}
}
return ans;
}
};
作者:bianchengxiong
链接:https://leetcode-cn.com/problems/trapping-rain-water-ii/solution/acmjin-pai-ti-jie-zui-duan-lu-suan-fa-bi-zdax/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
743 网络延迟时间 Dijkstra
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
# 邻接矩阵
g = [[float('inf')] * n for _ in range(n)]
for x, y, time in times:
g[x - 1][y - 1] = time
# 距离数组
dist = [float('inf')] * n
dist[k - 1] = 0
# 标记数组
used = [False] * n
for _ in range(n):
# 找到未标记最近的点
x = -1
for y, u in enumerate(used):
if not u and (x == -1 or dist[y] < dist[x]):
x = y
# 更新
used[x] = True
for y, time in enumerate(g[x]):
dist[y] = min(dist[y], dist[x] + time)
ans = max(dist)
return ans if ans < float('inf') else -1
作者:已注销
链接:https://leetcode-cn.com/problems/network-delay-time/solution/gtalgorithm-dan-yuan-zui-duan-lu-chi-tou-w3zc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
bfs
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
"""广度优先搜索"""
# 建图 - 邻接表
mp = [{} for i in range(n + 1)]
for u, v, t in times:
mp[u][v] = t
# 记录结点最早收到信号的时间
res = [-1 for _ in range(n + 1)]
res[k] = 0
# 队列中存放 [结点,收到信号时间]
import collections
deque = collections.deque()
deque.append((k,0))
while deque:
cur_node, t = deque.popleft()
for next_node, need_time in mp[cur_node].items():
art = t + need_time
# 仅当结点未收到或收到时间比记录时间更早才更新并入队
if res[next_node] == -1 or art < res[next_node]:
res[next_node] = art
deque.append([next_node, art])
minT = -1
for i in range(1, n + 1):
if res[i] == -1:
return -1
minT = max(minT, res[i])
return minT
dfs
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
"""深度优先搜索"""
# 建图 - 邻接表
mp = [{} for i in range(n + 1)]
for u, v, t in times:
mp[u][v] = t
# 记录结点最早收到信号的时间
r = [-1 for i in range(n + 1)]
def dfs(i: int, t: int) -> None:
"""在 t 时间到达 i 结点"""
if r[i] == -1 or t < r[i]:
r[i] = t
for u, v in mp[i].items():
dfs(u, t + v)
dfs(k, 0)
minT = -1
for i in range(1, n + 1):
if r[i] == -1:
return -1
minT = max(minT, r[i])
return minT
作者:meteordream
链接:https://leetcode-cn.com/problems/network-delay-time/solution/wang-luo-yan-chi-shi-jian-dan-yuan-zui-d-m1m3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2157. 字符串分组
class Solution(object):
def groupStrings(self, words):
"""
:type words: List[str]
:rtype: List[int]
"""
#判断两个单词的编辑距离
def edite_distance(word1,word2):
dp=[[0 for i in range(len(word2)+1)] for _ in range(len(word1)+1)]
#初始化
for i in range(len(word2)+1):
dp[0][i]=i
for i in range(len(word1)+1):
dp[i][0]=i
#两层循环
for i in range(1,len(word1)+1):
for j in range(1,len(word2)+1):
if word1[i-1]==word2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
#word1删去一个元素
c1=dp[i-1][j]+1
#word2删去一个元素
c2=dp[i][j-1]+1
#改变一个元素
c3=dp[i-1][j-1]+1
dp[i][j]=min(c1,c2,c3)
return dp[-1][-1]
res1=[]
#广度优先遍历即可
visited=set()
for i in range(len(words)):
if words[i] not in visited:
cur_node=[]
cur_node.append(words[i])
visited.add(words[i])
cur_res=[]
while cur_node:
cur_word2=cur_node.pop(0)
cur_res.append(cur_word2)
for j in range(len(words)):
if words[j] not in visited and cur_word2!=words[j]:
# 判断是否关联
if edite_distance(cur_word2,words[j])==1:
cur_node.append(words[j])
visited.add(words[j])
res1.append(cur_res[:])
print(res1)
res=[]
res.append(len(res1))
a=0
for i in range(len(res1)):
a=max(a,len(res1[i]))
res.append(a)
return res
这么做能通过一些case,但是,题目要求是字符串集合是否相似,是不考虑前后顺序的。所以得用二进制。
1219 黄金矿工
回溯
得用回溯,因为不回溯的话两圈之间会互相影响。
class Solution:
def getMaximumGold(self, grid: List[List[int]]) -> int:
#不能同时计算两个方向的,因此用dfs一搜到底
directions=[(-1,0),(1,0),(0,-1),(0,1)]
def dfs(i,j):
a1,a2,a3,a4=0,0,0,0
if i+1<len(grid) and grid[i+1][j]!=0 and (i+1,j) not in visited:
visited.add((i+1,j))
a1=dfs(i+1,j)+grid[i+1][j]
visited.remove((i+1,j))
if i-1>=0 and grid[i-1][j]!=0 and (i-1,j) not in visited:
visited.add((i-1,j))
a2=dfs(i-1,j)+grid[i-1][j]
visited.remove((i-1,j))
if j+1<len(grid[0]) and grid[i][j+1]!=0 and (i,j+1) not in visited:
visited.add((i,j+1))
a3=dfs(i,j+1)+grid[i][j+1]
visited.remove((i,j+1))
if j-1>=0 and grid[i][j-1]!=0 and (i,j-1) not in visited:
visited.add((i,j-1))
a4=dfs(i,j-1)+grid[i][j-1]
visited.remove((i,j-1))
return max(a1,a2,a3,a4)
res=0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j]!=0:
visited=set()
visited.add((i,j))
cur_ans=grid[i][j]+dfs(i,j)
print((i,j),cur_ans)
res=max(res,cur_ans)
return res
回溯:用修改gird的方法,来防治往回走,代码简洁,类似于 单词搜索。
#从各个起点开始搜索,用grid[i][j]来标记走过的点,回溯。
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def getMaximumGold(self, grid):
# 往上下左右四个方向走
def dfs(start_i,start_j):
if start_i < 0 or start_i > len(grid)-1 or start_j < 0 or start_j > len(grid[0]) - 1 or grid[start_i][start_j] <= 0:
return 0
tmp = grid[start_i][start_j]
grid[start_i][start_j] = -1
a1 = dfs(start_i+1,start_j) + tmp
a2 = dfs(start_i - 1,start_j) + tmp
a3 = dfs(start_i, start_j + 1)+ tmp
a4 = dfs(start_i, start_j - 1)+ tmp
grid[start_i][start_j] = tmp
return max(a1,a2,a3,a4)
res = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] > 0:
cur_res = dfs(i,j)
res = max(res,cur_res)
return res
bfs:不太行
下面第一个是我写的bfs,通不过全部的case。
因为在bfs遍历的时候有一个visited数组,两圈之间可能会互相影响。
要是用bfs得用下面第二种那样,把visited加到队列里。
class Solution:
def getMaximumGold(self, grid):
# bfs板子题
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
res = 0
from collections import deque
deque = deque()
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] != 0:
cur_ans = 0
visited = set()
deque.append(((i, j), grid[i][j]))
visited.add((i, j))
while deque:
(x, y), value = deque.popleft()
cur_ans =max(cur_ans,value)
for derection in directions:
new_dx = x + derection[0]
new_dy = y + derection[1]
if new_dx >= 0 and new_dx < len(grid) and new_dy >= 0 and new_dy < len(grid[0]) and (
new_dx, new_dy) not in visited:
deque.append(((new_dx, new_dy), value+grid[new_dx][new_dy]))
visited.add((new_dx, new_dy))
print((i, j), cur_ans)
res = max(res, cur_ans)
return res
class Solution:
def getMaximumGold3(self, grid) -> int:
dirs = {(0, 1), (0, -1), (-1, 0), (1, 0)}
m, n = len(grid), len(grid[0])
ans = 0
for i in range(m):
for j in range(n):
if grid[i][j]:
q = deque([(i, j, grid[i][j], set([(i, j)]))])
while q:
x, y, v, vis = q.popleft()
ans = max(ans, v)
for dx, dy in dirs:
if 0 <= x + dx < m and 0 <= y + dy < n and grid[x + dx][y + dy] and (
x + dx, y + dy) not in vis:
q.append((x + dx, y + dy, v + grid[x + dx][y + dy], vis | set([(x + dx, y + dy)])))
return ans
2050. 并行课程 III
分层bfs遍历
这么做只能通过一部分case.因为实际上并不是按照分层来的,比如上面那个例子,假如节点1的时间是10,那么节点1和其他节点的时间是并行的。
class Solution:
def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
#拓扑排序,记录每层的最大value
#先建图
graph=[[] for _ in range(n+1)]
indegree=[0 for _ in range(n+1)]
for pre,cur in relations:
graph[pre].append(cur)
indegree[cur]+=1
print(indegree)
print(graph)
#找到入度为0的节点
from collections import deque
deq=deque()
for i in range(1,len(indegree)):
if indegree[i]==0:
deq.append((i,time[i-1]))
res=0
while deq:
cur_level_max_time=0
loop_count=len(deq)
print(loop_count)
deque_next=deque()
while loop_count>0:
cur,cur_time =deq.popleft()
cur_level_max_time=max(cur_level_max_time,cur_time)
next_courses=graph[cur]
print(next_courses)
for next_course in next_courses:
indegree[next_course]-=1
if indegree[next_course]==0:
deque_next.append((next_course,time[next_course-1]))
loop_count-=1
deq=deque_next
res+=cur_level_max_time
return res
bfs+动态规划
用dp[next_course] = max(dp[next_course], dp[cur] + time[next_course - 1])
来更新,到当前节点所需要的最大时间。
class Solution:
def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
#拓扑排序,记录每层的最大value
#先建图
graph = [[] for _ in range(n + 1)]
indegree = [0 for _ in range(n + 1)]
dp = [0 for _ in range(n + 1)]
for pre, cur in relations:
graph[pre].append(cur)
indegree[cur] += 1
# 找到入度为0的节点
from collections import deque
deq = deque()
for i in range(1, len(indegree)):
dp[i] = time[i - 1]
if indegree[i] == 0:
deq.append(i)
while deq:
loop_count = len(deq)
deque_next = deque()
while loop_count > 0:
cur = deq.popleft()
#计算时间,前置任务的最大时间,加上当前节点的时间
next_courses = graph[cur]
for next_course in next_courses:
indegree[next_course] -= 1
dp[next_course] = max(dp[next_course], dp[cur] + time[next_course - 1])
if indegree[next_course] == 0:
deque_next.append(next_course)
loop_count -= 1
deq = deque_next
return max(dp)
6063. 节点序列的最大得分
枚举边,脑筋急转弯
dfs肯定超时
class Solution:
def maximumScore(self, scores: List[int], edges: List[List[int]]) -> int:
child = defaultdict(set)
for a, b in edges:
child[a].add(b)
child[b].add(a)
ans = -1
edges.sort(key=lambda i:scores[i[0]] + scores[i[1]], reverse=True)
for i in range(len(edges)):
a, b = edges[i]
for j in range(i + 1, len(edges)):
c, d = edges[j]
# 有重复点时跳过
if a == c or a == d or b == c or b == d:
continue
tmp = scores[a] + scores[b] + scores[c] + scores[d]
if tmp > ans:
# 两边连通
if a in child[c] or a in child[d] or b in child[c] or b in child[d]:
ans = max(ans, tmp)
else: # 后面找不到更好的边了
break
return ans
作者:you-zhu-yi-si-mou-mou-ren
链接:https://leetcode-cn.com/problems/maximum-score-of-a-node-sequence/solution/-by-you-zhu-yi-si-mou-mou-ren-1jtv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6134. 找到离给定两个节点最近的节点
我的错误的做法,有的case不能通过
class Solution(object):
def closestMeetingNode(self, edges, node1, node2):
"""
:type edges: List[int]
:type node1: int
:type node2: int
:rtype: int
"""
import collections
graph = collections.defaultdict(int)
for i in range(len(edges)):
graph[i] = edges[i]
print(graph)
if_circle = False
path1 = [node1]
next_node = graph[node1]
while next_node not in path1 and next_node!= -1:
if next_node == node2:
if_circle = True
path1.append(next_node)
next_node = graph[next_node]
path2 = [node2]
next_node = graph[node2]
while next_node not in path2 and next_node!= -1:
if next_node == node1:
if_circle = True
path2.append(next_node)
next_node = graph[next_node]
print(path1,path2)
print(if_circle)
if not if_circle:
a = [i for i in path1 if i in path2]
print(a)
if len(a) > 0:
return a[0]
return -1
else:
path2_back = path2[::-1]
a1 = [i for i in path1 if i in path2_back]
path1_back = path1[::-1]
a2 = [i for i in path1_back if i in path2]
print(a1,a2)
#到a1的距离
count1 = 0
for i in range(len(path1)):
if path1[i] == a1[0]:
break
count1 += 1
count2 = 0
for i in range(len(path2)):
if path2[i] == a2[0]:
break
count2 += 1
if count1 != count2:
if count1 < count2:
return a1[0]
return a2[0]
else:
if a1[0] < a2[0]:
return a1[0]
return a2[0]
# if a1[0] > a2[0]:
# return a2[0]
# return a1[0]
# edges = [1,2,-1]
# node1 = 0
# node2 = 2
# # edges = [2,2,3,-1]
# node1 = 0
# node2 = 1
# edges = [5,-1,3,4,5,6,-1,-1,4,3]
# node1 = 0
# node2 = 0
# edges = [4,3,0,5,3,-1]
# node1 = 4
# node2 = 0
# 4
# edges = [4,4,4,5,1,2,2]
# node1 = 1
# node2 =1
# edges = [2,0,0]
# node1 = 2
# node2 = 0
#0
# edges = [5,3,1,0,2,4,5]
# node1 = 3
# node2 = 2
#3
# edges = [5,4,5,4,3,6,-1]
# node1 = 0
# node2 = 1
edges = [-1,7,15,15,-1,4,16,2,16,7,11,6,10,4,9,1,14,-1]
node1 = 1
node2 = 6
res = Solution().closestMeetingNode(edges, node1, node2)
print(res)
正确的解法
class Solution:
def closestMeetingNode(self, edges: List[int], node1: int, node2: int) -> int:
# BFS计算给定节点u到其后代节点的距离
def bfs(u):
visited = dict()
step = 0
while u != -1 and u not in visited:
visited[u] = step
u = edges[u] # 节点u的子代节点
step += 1
return visited
# 分别计算node1和node2到其后代节点的距离
visited1 = bfs(node1)
visited2 = bfs(node2)
ans = (-1, 10**9) # (节点编号,对应距离的较大值)
for node in visited1:
if node in visited2:
dist = max(visited1[node], visited2[node]) # 更新结果
if dist < ans[1] or (dist == ans[1] and node < ans[0]):
ans = (node, dist)
return ans[0]
作者:flix
链接:https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/by-flix-nk4w/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6135. 图中的最长环
class Solution(object):
def longestCycle(self, edges):
"""
:type edges: List[int]
:rtype: int
"""
import collections
graph = collections.defaultdict(int)
for i in range(len(edges)):
graph[i] = edges[i]
res = -1
visited = set()
for i in range(len(edges)):
start_node = i
cur_node = start_node
# 哈希表记录路径上点到起点的距离
dist = collections.defaultdict(int)
d = 0
while cur_node not in visited:
visited.add(cur_node)
dist[cur_node] = d
d += 1
cur_node = graph[cur_node]
if cur_node == -1:
break
if cur_node in dist:
pre = dist[cur_node]
now = d
res = max(res,now - pre)
break
return res
1210. 穿过迷宫的最少移动次数
class Solution:
def minimumMoves(self, g: List[List[int]]) -> int:
step, n = 1, len(g)
vis = {(0, 0, 0)}
q = [(0, 0, 0)] # 初始位置
while q:
tmp = q
q = []
for X, Y, S in tmp:
for t in (X + 1, Y, S), (X, Y + 1, S), (X, Y, S ^ 1): # 直接把移动后的位置算出来
x, y, s = t
x2, y2 = x + s, y + (s ^ 1) # 蛇头
if x2 < n and y2 < n and t not in vis and \
g[x][y] == 0 and g[x2][y2] == 0 and (s == S or g[x + 1][y + 1] == 0):
if x == n - 1 and y == n - 2: # 此时蛇头一定在 (n-1,n-1)
return step
vis.add(t)
q.append(t)
step += 1
return -1
作者:endlesscheng
链接:https://leetcode.cn/problems/minimum-moves-to-reach-target-with-rotations/solution/huan-zai-if-elseyi-ge-xun-huan-chu-li-li-tw8b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。