当前位置: 首页 > news >正文

[leetcode] 图论算法(DFS和BFS)

一、DFS

1.连通块

547. 省份数量 [Medium]
1971. 寻找图中是否存在路径 [Simple]
797. 所有可能的路径 [Medium]
841. 钥匙和房间 [Medium]
2316. 统计无向图中无法互相到达点对数 [Medium]
1319. 连通网络的操作次数 [Medium]
2492. 两个城市间路径的最小分数 [Medium]
3310. 移除可疑的方法 [Medium]
2685. 统计完全连通分量的数量 [Medium]
2192. 有向无环图中一个节点的所有祖先 [Medium]
399. 除法求值 [Medium]
133. 克隆图 [Medium]

# 2685. 统计完全连通分量的数量
class Solution:def countCompleteComponents(self, n: int, edges: List[List[int]]) -> int:d=defaultdict(list)for a,b in edges:d[a].append(b)d[b].append(a)vis=[False]*ndef dfs(i):vis[i]=Truenonlocal e,vv+=1e+=len(d[i])for j in d[i]:if not vis[j]:dfs(j)ans=0           for i in range(n):if not vis[i]:e=v=0dfs(i)ans+=(e==v*(v-1))return ansclass Solution:def countCompleteComponents(self, n: int, edges: List[List[int]]) -> int:# 建图g = defaultdict(list)for a,b in edges:g[a].append(b)g[b].append(a)# dfsdef dfs(i):vis.add(i)nonlocal e,vv += 1# e必须放在外面加e += len(g[i])for j in g[i]:if j not in vis:# e不能在里面加,因为标记访问过后,最后一条边进不来dfs(j)# 创建访问标记vis,ans = set(),0for i in range(n):if i not in vis:e = v = 0dfs(i)ans += (e == v*(v-1))return ans

连通块相关的题目主要是三个步骤:1>建图;2>创建访问标记变量;3>dfs。
访问标记变量有两种方法,一种是创建数组vis=[False]*n,另一种是创建集合vis = set(),两种都可以看个人喜好。dfs中的步骤基本也是固定的,先标记访问当前节点,然后遍历当前节点的下游连通节点,如果下游连通节点还没访问过,就递归dfs。

2.标记访问进阶

207. 课程表 [Medium]
802. 找到最终的安全状态 [Medium]
210. 课程表 II [Medium]
2115. 从给定原材料中找到所有可以做出的菜 [Medium]

第一类中的标记访问方法,可以避免重复访问以及防止图中有环出现无限递归。但是无法处理下面这种情况:
在这里插入图片描述
比如说我想要求出节点1出发的所有路径,如果采用第一类中的标记方法,节点3在第一条路径访问时被标记过了,那么在遍历第二条路径时就会跳过,从而漏掉第二条路径。解决方法是三色标记法(具体见灵神题解)

class Solution:def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:g=defaultdict(list)for a,b in prerequisites:g[a].append(b)def dfs(i):vis[i]=1for j in g[i]:# 出现互相依赖关系,即出现环if vis[j]==1 or (vis[j]==0 and dfs(j)):return Truevis[i]=2return Falsevis=[0]*numCourses for i in range(numCourses):if not vis[i] and dfs(i):return Falsereturn True

采用三色标记法,1表示中间状态,2表示成功状态。如果在一次遍历中,访问到了状态为1的节点,则表示出现了循环依赖关系,即出现了环,那么当前这条路径就是非法的。可以看出这类题目只能用创建数组来标记访问,不适用创建集合来标记访问。

二、BFS

210. 课程表 II [Medium]
3243. 新增道路查询后的最短距离 I [Medium]
1311. 获取你好友已观看的视频 [Medium]
909. 蛇梯棋 [Hard]
127. 单词接龙 [Medium]
433. 最小基因变化 [Medium]

# 1311. 获取你好友已观看的视频
class Solution:def watchedVideosByFriends(self, watchedVideos: List[List[str]], friends: List[List[int]], id: int, level: int) -> List[str]:all,vis=[],[False]*len(friends)q=deque([id])vis[id]=Truefor i in range(level):cur_len=len(q)tmp=[]for j in range(cur_len):front=q.popleft()for k in friends[front]:if not vis[k]:vis[k]=Truetmp.append(k)q.extend(tmp)for j in q:all+=watchedVideos[j]    ans=Counter(all)ans=sorted(ans.items(),key=lambda x:(x[1],x[0]))return [k for k,v in ans]

这题就是常规的BFS题目,套路就是先求当前level的长度cur_len,然后遍历队首,将符合条件的元素再插到队尾。

# 127. 单词接龙
class Solution:def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:if endWord not in set(wordList):return 0def diff(a,b):cnt=0for x,y in zip(a,b):cnt+=1 if x!=y else 0if cnt>1:return Falsereturn True if cnt==1 else Falseg=defaultdict(list)for a,b in combinations(wordList+[beginWord],2):if diff(a,b):g[a].append(b)g[b].append(a)q,vis=deque([(beginWord,1)]),set([beginWord])while q:front,v=q.popleft()for j in g[front]:if j==endWord:return v+1if j not in vis:# 防止重复访问vis.add(j)q.append((j,v+1))return 0

剩下的题目跟传统的BFS题思路略有不同,它不会先去取当前level的个数,而是只看队首,只要满足条件了立即返回,所以题目中会有类似“最短距离”、“最少次数”这样的字眼。

这类BFS题目几个注意点:
1.队列中存的是元组(元素,次数/步数);
2.取出队首元素,遍历队首元素的连通节点,只要找到目标节点了,立即返回;
3.元素在被添加到队列末尾的时候就加到vis集合中,第一时间标记访问,防止后面重复添加。不要在取出队首元素的时候加到vis集合中,这样有可能会重复添加同一个节点,造成重复访问。



题目参考自leetcode 灵神题单:
https://leetcode.cn/discuss/post/3581143/fen-xiang-gun-ti-dan-tu-lun-suan-fa-dfsb-qyux/

http://www.dtcms.com/a/301186.html

相关文章:

  • Java“class file contains wrong class”解决
  • NX868NX872美光固态闪存NX873NX876
  • 疯狂星期四文案网第21天运营日记
  • 10.模块与包:站在巨人的肩膀上
  • 去除视频字幕 5: 使用 ProPainter, 记录探索过程
  • red靶机
  • MCU 通用AT指令处理框架
  • 洛谷 P2114 [NOI2014] 起床困难综合症-普及+/提高
  • AutoLabelImg:高效的数据自动化标注工具和下载
  • 风光氢系统仿真与容量扩展设计
  • 飞牛NAS本地化部署n8n打造个人AI工作流中心
  • 识别身份证用证件号或姓名改名,如何ocr识别身份证复印件并导出至excel表格?身份证读取软件导出到Excel乱码怎么解决?
  • LLM 多语言数据集
  • 华为OD机试_2025 B卷_书籍叠放(Python,200分)(附详细解题思路)
  • Coze Studio概览(一)
  • 力扣131:分割回文串
  • 详解赛灵思SRIO IP并提供一种FIFO封装SRIO的收发控制器仿真验证
  • 2025年Agent创业实战指南:从0到1打造高增长AI智能体项目
  • FPGA IP升级
  • input_handler和input_dev详解
  • 【AI阅读】20250717阅读输入
  • 深度学习在计算机视觉中的应用:对象检测
  • C++ auto 类型推导
  • Netty中 ? extends Future<? super V>这种的写法的理解
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 73(题目+回答)
  • PDF文件被加密限制怎么办?专业级解除方案分享
  • mysql 快速上手
  • FFmpeg——参数详解
  • 3.JDK+JRE组件构成与协作
  • LeetCode 923.多重三数之和