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

LeetCode-547. 省份数量

1、题目描述:

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

示例 1:

输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2

示例 2:

输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3

提示:

  • 1 <= n <= 200
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][j] 为 1 或 0
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

2、代码:

#include <vector>
#include <functional>  // 用于lambda表达式

using namespace std;

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        // 获取城市数量
        int n = isConnected.size();
        if (n == 0) return 0;

        // 初始化并查集数据结构
        vector<int> parent(n);   // parent[i]表示i的父节点
        vector<int> rank(n, 1); // rank[i]表示以i为根的树的高度(用于按秩合并)

        // 初始时每个城市自成一类,父节点指向自己
        for (int i = 0; i < n; ++i) {
            parent[i] = i;
        }

        // 查找函数(带路径压缩)
        // 作用:找到x的根节点,并将路径上的节点直接指向根(降低后续查找复杂度)
        function<int(int)> find = [&](int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);  // 递归压缩路径
            }
            return parent[x];
        };

        // 合并函数(按秩合并优化)
        // 作用:将x和y所在的集合合并为一个集合
        auto unite = [&](int x, int y) {
            int rootX = find(x);  // 找到x的根
            int rootY = find(y);  // 找到y的根
            
            // 关键修复:必须检查根是否相同,否则会导致错误合并
            if (rootX == rootY) return;  // 已在同一集合中,无需合并

            // 按秩合并:将小树合并到大树下以保持平衡
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;  // 将rootX的父设为rootY
            } else {
                parent[rootY] = rootX;  // 将rootY的父设为rootX
                // 若两树高度相同,合并后树的高度+1
                if (rank[rootX] == rank[rootY]) {
                    ++rank[rootX];  // 仅在两树同高时增加秩
                }
            }
        };

        // 遍历邻接矩阵的上三角部分(利用对称性避免重复处理)
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {  // 仅处理i<j的情况
                if (isConnected[i][j] == 1) {  // 发现相连城市
                    unite(i, j);  // 合并集合
                }
            }
        }

        // 统计连通分量数量(即根节点数量)
        int provinces = 0;
        for (int i = 0; i < n; ++i) {
            // 根节点的特征是:find(i) == i
            if (find(i) == i) {
                ++provinces;
            }
        }

        return provinces;
    }
};

3、解题思路:

注:该题建议使用并查集的思想去解决,因为并查集就是用来解决与动态连通性相关的问题

  1. 初始化并查集:每个城市初始时独立,父节点指向自己,秩初始化为1。
  2. 查找函数(带路径压缩)​:递归查找根节点,并将路径上的节点直接连接到根节点,减少后续查找时间。
  3. 合并函数(按秩合并)​:根据秩的大小合并两个集合,保持树的平衡性,避免树过高。
  4. 遍历邻接矩阵:仅处理上三角部分,避免重复合并相连的城市对。
  5. 统计连通分量:遍历所有城市,统计根节点的数量,每个根节点代表一个省份。
http://www.dtcms.com/a/107401.html

相关文章:

  • 【求稳方案】基于树莓派+深度相机的慧眼识果完整实现方案
  • Scala-面向对象
  • xml文件中的gt;
  • 【Linux篇】探索进程地址空间:计算机背后的虚拟世界
  • 笔记2——网络参考模型
  • 前端JS高阶技法:序列化、反序列化与多态融合实战
  • 逆向工程核心原理-第二章-helloworld
  • 【一起来学kubernetes】34、ReplicaSet使用详解
  • SpringKafka消息发布:KafkaTemplate与事务支持
  • 传统可视化工具与新兴工具,到底该如何抉择?
  • py数据结构day3
  • idea gitlab 操作
  • 算法设计学习5
  • 【Windows+Cursor】从0到1配置Arxiv MCP Server,实现论文自主查询、下载、分析、综述生成
  • 从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.1LangChain与Dify平台实战:从RAG到Agent工作流
  • 基于Python的医院信息管理系统的设计与实现
  • 【C#实战】动态模板替换:根据Model字段名称自动匹配替换值【代码之美】
  • 货代业务数字化管理:易境通货代系统在转型中的应用
  • 7.3 分治-快排:LeetCode 215.数组中的第K个最大元素
  • CompletableFuture 与反应式编程:异步编程的两种范式对比与实战
  • 简化Rust开发:探索lombok-macros crate
  • 01-性能测试
  • 【NLP 52、多模态相关知识】
  • Redis的Lua脚本
  • Docker 安装 Elasticsearch 教程
  • 人工智能之数学基础:基于吉文斯变换完成矩阵的QR分解
  • leetcode-热题100(3)
  • 【Triton 教程】triton_language.arange
  • 【C++】vector的模拟实现
  • 【AI插件开发】Notepad++ AI插件开发实践(代码篇):从Dock窗口集成到功能菜单实现