Swift 图论实战:DFS 算法解锁 LeetCode 323 连通分量个数


文章目录

摘要

图是算法中最具挑战性的结构之一,而"连通分量"这个词听起来也有点像社交网络里的"圈子"概念。给你一张无向图,节点编号从 0 到 n-1,现在请你找出这个图中到底有多少个互相连着的群体(连通分量)

这题其实在很多实际问题里都能找到身影,比如社交图谱分析、网络故障检测、孤岛计算等等。

这篇文章将用 Swift 带你搞懂这题背后的图遍历方法(DFS 和并查集两种思路),并提供完整代码与解释。

描述

给定一个由 n 个节点(编号为 0n - 1)组成的无向图和一个边列表 edges,请你计算图中连通分量的数量。

示例

输入:

swift 复制代码
n = 5
edges = [[0, 1], [1, 2], [3, 4]]

输出:

txt 复制代码
2

解释:图中有两个连通分量:{0,1,2} 和 {3,4}

题解答案

这题有两个常见解法:

DFS 遍历每个连通区域

把图看成是一个邻接表,然后从没访问过的点开始 DFS,把一个区域内的所有点标记为访问过。每发现一个新未访问的节点,就说明有一个新的连通分量。

Union-Find(并查集)

通过并查集把每个点合并成"祖宗节点",合并所有连通的点,最后统计有多少个不同的祖宗节点,就是连通分量的数量。

我们下面会实现 DFS 方法,它更直观易懂,特别适合初学者。

题解代码分析(Swift 实现:DFS)

swift 复制代码
func countComponents(_ n: Int, _ edges: [[Int]]) -> Int {
    var graph = [Int: [Int]]()
    for edge in edges {
        graph[edge[0], default: []].append(edge[1])
        graph[edge[1], default: []].append(edge[0])
    }

    var visited = Set<Int>()
    var components = 0

    func dfs(_ node: Int) {
        if visited.contains(node) { return }
        visited.insert(node)
        for neighbor in graph[node, default: []] {
            dfs(neighbor)
        }
    }

    for i in 0..<n {
        if !visited.contains(i) {
            components += 1
            dfs(i)
        }
    }

    return components
}

题解代码详解

构建邻接表

swift 复制代码
var graph = [Int: [Int]]()
for edge in edges {
    graph[edge[0], default: []].append(edge[1])
    graph[edge[1], default: []].append(edge[0])
}

这段代码会把每一对连接关系存进字典,形成一个"谁连着谁"的列表。

DFS 深度优先搜索

swift 复制代码
func dfs(_ node: Int) {
    if visited.contains(node) { return }
    visited.insert(node)
    for neighbor in graph[node, default: []] {
        dfs(neighbor)
    }
}

从某个起点开始,一路访问下去,把整个连通区域的点都标记为"访问过"。

遍历所有节点

swift 复制代码
for i in 0..<n {
    if !visited.contains(i) {
        components += 1
        dfs(i)
    }
}

每当我们发现一个还没被访问的点,就说明它是一个新连通分量的起点,我们就从它出发去搜索这个"朋友圈"。

示例测试及结果

示例 1

swift 复制代码
let count1 = countComponents(5, [[0, 1], [1, 2], [3, 4]])
print(count1) // 输出:2

示例 2

swift 复制代码
let count2 = countComponents(4, [[0, 1], [2, 3]])
print(count2) // 输出:2

示例 3

swift 复制代码
let count3 = countComponents(5, [[0, 1], [1, 2], [2, 3], [3, 4]])
print(count3) // 输出:1

时间复杂度分析

  • 构建图:O(E)
  • DFS 总遍历所有节点和边:O(N + E)
  • 总体时间复杂度:O(N + E),其中 N 是节点数,E 是边数

空间复杂度分析

  • 图邻接表:O(N + E)
  • 访问集合:O(N)
  • DFS 栈空间:O(N)
  • 总体空间复杂度:O(N + E)

总结

这道题非常适合作为图算法入门练手题,掌握它你会收获:

  • 如何从边列表构建图结构
  • 如何用 DFS 找出连通区域
  • 连通分量的概念实际是"有几个不相交的图"
相关推荐
江畔柳前堤8 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore9 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考11 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX11 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面12 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号12 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽12 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI12 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者14 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者14 小时前
【征程6】校准量化中HistogramObserver解析
算法