List: 110. 字符串接龙,105.有向图的完全可达性,106. 岛屿的周长
110. 字符串接龙,105.有向图的完全可达性,106. 岛屿的周长
一段话总结:题目要求在给定的字典strList
中,从beginStr
转换到endStr
,每次只能改变一个字符且中间字符串必须在字典中,求最短转换序列的字符串数目,不存在则返回0。解题思路是通过枚举替换字符判断字符串间的连接关系,构建图结构,然后利用广度优先搜索(BFS)在无权图中求最短路,同时使用set
检查字符串是否在集合中,用map
记录访问情况和路径长度,防止死循环。还可尝试双向BFS优化。
strList
、起始字符串beginStr
和结束字符串endStr
,要求找出从beginStr
到endStr
的最短转换序列中的字符串数目。转换需满足:序列首为beginStr
,尾为endStr
;每次仅能改变一个位置的字符;中间字符串必须在strList
中;beginStr
和endStr
不在strList
中,且字符串仅由小写字母组成。若不存在转换序列,返回0。N
,表示strList
中字符串数量|
|第二行|两个字符串,用空格隔开,分别为beginStr
和endStr
|
|后续N
行|每行一个字符串,代表strList
中的字符串|
|输出|从beginStr
转换到endStr
最短转换序列的字符串数量,不存在则输出0|strList
中出现,则判断这两个字符串有连接。beginStr
和终点endStr
的最短路径,使用广度优先搜索(BFS)最合适。因为BFS以起点为中心向四周扩散搜索,搜到终点时的路径一定是最短的。而深度优先搜索(DFS)需在到达终点的不同路径中选择最短路,相对麻烦。unordered_map
来记录strList
里的字符串是否被访问过,同时记录路径长度,用unordered_set
检查字符串是否出现在字符串集合里,这样效率更高。unordered_set
存储strList
中的字符串,unordered_map
记录字符串的访问情况和路径长度,queue
实现BFS。在循环中,取出队列头部字符串,替换每个字符后检查是否为终点或在strList
中且未被访问过,若满足条件则更新路径长度并加入队列。若未找到路径则输出0。同时提到可以用双向BFS优化。unordered_set
和unordered_map
分别起到什么作用?
unordered_set
用于存储字典strList
中的字符串,在检查某个替换后的字符串是否在字典中时,使用unordered_set
的find
方法效率更高。unordered_map
用于记录strList
里的字符串是否被访问过,同时记录从起点到该字符串的路径长度,以此来避免重复访问和计算路径长度。from collections import deque
def judge(s1, s2):
count = 0
for i in range(len(s1)):
if s1[i] != s2[i]:
count += 1
return count == 1
n = int(input())
beginstr, endstr = map(str, input().split())
if beginstr == endstr:
print(0)
exit()
strlist = []
for _ in range(n):
strlist.append(input())
visited = [False for _ in range(n)]
que = deque()
que.append([beginstr, 1])
while que:
judgestr, step = que.popleft()
if judge(judgestr, endstr):
print(step + 1)
exit()
for i in range(n):
if visited[i] == False and judge(strlist[i], judgestr):
visited[i] = True
que.append([strlist[i], step + 1])
print(0)
N
个节点(节点编号为1到N
)和K
条边,判断从1号节点出发能否通过边到达任何节点。如果可以,输出1;否则,输出 -1。N
和K
,分别表示节点数量和边的数量|
|后续K
行|每行两个正整数s
和t
,表示从s
节点到t
节点有一条单向边|
|输出|1(1号节点可到达所有节点)或 -1(1号节点不能到达所有节点)|def dfs(graph, key, visited):
if visited[key]:
return
visited[key] = True
keys = graph[key]
for key in keys:
dfs(graph, key, visited)
n, m = map(int, input().split())
graph = {i: [] for i in range(1, n + 1)}
for _ in range(m):
s, t = map(int, input().split())
graph[s].append(t)
visited = [False for _ in range(n + 1)]
dfs(graph, 1, visited)
def check(visited):
for i in range(1, n + 1):
if visited[i] == False:
return -1
return 1
print(check(visited))
def dfs(graph, key, visited):
keys = graph[key]
for neighbor in keys:
if visited[neighbor] == False:
visited[neighbor] = True
dfs(graph, neighbor, visited)
n, m = map(int, input().split())
graph = {i: [] for i in range(1, n + 1)}
for _ in range(m):
s, t = map(int, input().split())
graph[s].append(t)
visited = [False for _ in range(n + 1)]
visited[1] = True
dfs(graph, 1, visited)
def check(visited):
for i in range(1, n + 1):
if visited[i] == False:
return -1
return 1
print(check(visited))
在深度优先搜索(DFS)中,所谓“处理当前层”和“处理下一层”的不同写法,主要体现在代码逻辑结构和对节点处理的时机上。下面以你之前关于判断有向图可达性的问题为例,详细解释这两种写法的差异及其原因:
def dfs(graph, current_key, visited):
if visited[current_key]:
return
visited[current_key] = True
neighbors = graph[current_key]
for neighbor in neighbors:
dfs(graph, neighbor, visited)
在这种写法中:
current_key
是否已经被访问过(if visited[current_key]: return
),如果已访问则直接返回,不再继续处理。如果未访问,则将其标记为已访问(visited[current_key] = True
),这是对当前节点的处理。neighbors = graph[current_key]
),然后通过循环对每个邻接节点递归调用 dfs
函数(dfs(graph, neighbor, visited)
),从而进入下一层的搜索。这种写法是先处理完当前节点的标记等操作,再递归进入下一层。def dfs(graph, current_key, visited):
neighbors = graph[current_key]
for neighbor in neighbors:
if not visited[neighbor]:
visited[neighbor] = True
dfs(graph, neighbor, visited)
在这种写法中:
current_key
进行已访问的判断和标记操作。而是直接获取当前节点的邻接节点(neighbors = graph[current_key]
)。for neighbor in neighbors:
),对每个邻接节点进行判断,如果未被访问(if not visited[neighbor]:
),则将其标记为已访问(visited[neighbor] = True
),然后递归调用 dfs
函数进入下一层(dfs(graph, neighbor, visited)
)。这种写法是在处理下一层节点时,顺便处理节点的访问标记等操作,重点更偏向于快速进入下一层的搜索。两种写法在本质上都是深度优先搜索,只是对节点处理的时机和代码结构有所不同,在实际应用中可以根据具体需求和个人习惯选择合适的写法。
from collections import deque
n, m = map(int, input().split())
graph = {i: [] for i in range(1, n + 1)}
for _ in range(m):
s, t = map(int, input().split())
graph[s].append(t)
visited = [False for _ in range(n + 1)]
visited[1] = True
que = deque()
que.append(1)
while que:
key = que.popleft()
keys = graph[key]
for neighbor in keys:
if visited[neighbor] == False:
que.append(neighbor)
visited[neighbor] = True
def check(visited):
for i in range(1, n + 1):
if visited[i] == False:
return -1
return 1
print(check(visited))
岛屿问题最容易让人想到BFS或者DFS,但本题确实还用不上。
1
(陆地)和0
(水)组成的矩阵中岛屿的周长,矩阵外均为水,岛屿由水平或垂直相邻的陆地构成,陆地边长为1。提供了两种解法,解法一是遍历每个节点,遇到陆地时检查其上下左右,若周边是水域或出界则周长加1;解法二是先算出陆地总数乘以4,再减去相邻陆地对数乘以2,避免重复计算。同时给出了C++、Java、Python等语言的代码示例。1
(陆地)和0
(水)组成的矩阵,岛屿被水包围且通过水平或垂直相邻的陆地连接,假设矩阵外均是水,岛屿内部无水域,陆地边长为1
,计算岛屿周长。N
、M
,表示矩阵的行数和列数|
|后续N
行|每行M
个数字(1
或0
),代表岛屿单元格|
|输出|一个整数,表示岛屿的周长|1
)时,检查其上下左右四个方向的节点情况。若周边节点是水域(值为0
)或出界,则该陆地对应的这条边属于岛屿周长,周长加1
。4
条边,即陆地数量乘以4
。由于相邻的两个陆地会共用一条边,需要统计相邻陆地的数量(相邻对数),每对相邻陆地会使总边数减少2
,最终结果为陆地数量乘以4
减去相邻对数乘以2
。在统计相邻陆地时,为避免重复计算,只统计陆地的上边和左边相邻陆地。4
再减去相邻陆地对数乘以2
,岛屿内部水域会干扰陆地数量和相邻对数的正确统计,无法得出正确周长。direction
数组的作用是什么?
direction
数组用于表示陆地节点上下左右四个方向的偏移量。在检查陆地节点周边情况时,通过数组中的偏移量,计算出周边节点的坐标,进而判断周边节点是否是水域或出界,以此确定是否要将当前陆地对应的边计入周长。例如,direction[0]
表示向右的偏移量,可通过它计算出当前陆地右边节点的坐标。direction = [(0, 1), (1, 0), (0, -1), (-1, 0)]
n, m = map(int, input().split())
grid = []
for _ in range(n):
row = list(map(int, input().split()))
grid.append(row)
result = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
for k in range(4):
nx = i + direction[k][0]
ny = j + direction[k][1]
if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]) or grid[nx][ny] == 0:
result += 1
print(result)
n, m = map(int, input().split())
grid = []
for _ in range(n):
row = list(map(int, input().split()))
grid.append(row)
island = 0 #陆地数量
cover = 0 #相邻数量
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
island += 1 #统计总的陆地数量
if i - 1 >= 0 and grid[i - 1][j] == 1: #统计上边相邻陆地
cover += 1
if j - 1 >= 0 and grid[i][j - 1] == 1: #统计左边相邻陆地
cover += 1
#为什么没统计下边和右边? 因为避免重复计算
print(island * 4 - cover * 2)