[數據結構高階]并查集初識、手撕、可以解決哪類問題?

標題:[數據結構高階]并查集初識、手撕、可以解決哪類問題?
@水墨不寫bug


在這里插入圖片描述


文章目錄

  • 一、認識并查集
  • 二、模擬實現并查集
  • 三、用并查集解決問題
    • 1、[省份的數量](https://leetcode.cn/problems/number-of-provinces/)
    • 2、[等式方程的可滿足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/)
  • 四、并查集的路徑壓縮


一、認識并查集

一個考察隊要去西部開發考察,這個考察隊隊員有10人,其中鄭州4人,北京3人,西安3人。于是這三個城市的人由于生活習慣相似分別抱團,那么如何快速確定兩個人是否屬于同一個城市呢?并查集就可以。

并查集 :本質是一個森林(包含多棵樹)。并且與堆類似,用下標表示關系。使用雙親表示法(只存儲雙親)。
如何用數據結構表示并查集?
用一個線性結構(數組)表示。每一個位置都初始化為-1,表示10棵樹:
在這里插入圖片描述
假如0,6,7,8是鄭州人1,4,9是北京人2,3,5是西安人,那么通過樹形結構表示(默認下標最小的0,1,2作為小隊長- - -根節點):
在這里插入圖片描述
如果有新成員加入?
數組對應的隊員的值存儲的是隊長的下標,隊長的值的絕對值表示包括隊長在內的小隊成員個數。隊長的值原來為-1,一個隊員加入小隊,隊長的值+=隊員的值(-1)|如果隊員是隊長,則+=(-m),然后隊員的值修改為隊長的值。

在線性的數組上,需要明確:

  • 1.一個位置值是負數,那它就是數的根,這個負數的絕對值就是這棵樹的數據個數。
  • 2.一個位置值是正數,那這個位置存的是雙親的下標。

那么上圖對應的線性結構是:
在這里插入圖片描述

如果兩隊伍合并?
由于研究工作需要,北京人和鄭州人需要合并,那么在數據結構上如何表示?
其實,把北京人合并入鄭州,把鄭州人合并入北京,沒有本質區別。
假如把北京人合并入鄭州,那么對應的樹形結構變成:
在這里插入圖片描述
那么對應的線性結構:
在這里插入圖片描述
這就是并查集的加入一個成員,一個小隊的操作。想要看兩個隊員是否在同一組,只需要不停找根,如果兩個隊員同根,那就在同一組。


二、模擬實現并查集

并查集可以通過一個STL的vector維護,具體實現思路已經在上文有所體現,于是在這里直接給出實現:

#pragma once
#include<iostream>
#include<vector>
namespace ddsm
{class UnionFindSet{public://根據并查集規則,初始化為-1UnionFindSet(int size):_ufs(size,-1){}//把兩個集合【隊伍】合并void Union(int x1,int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2)return;_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//找到一個元素所在的集合int FindRoot(int x){int parents = x;while (_ufs[parents] >= 0)parents = _ufs[parents];return parents;}//判斷兩個元素是否在同一個集合bool InSameSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}//返回集合的個數size_t Size(){size_t size = 0;for (int i = 0; i < _ufs.size(); ++i){if (_ufs[i] < 0)size++;}return size;}private:std::vector<int> _ufs;};
};

三、用并查集解決問題

通過以上例子可知,并查集一般可以解決一下問題:

  1. 查找元素屬于哪個集合 --沿著數組表示樹形關系以上一直找到根(即:樹中中元素為負數的位置)
  2. 查看兩個元素是否屬于同一個集合 --沿著數組表示的樹形關系往上一直找到樹的根,如果根相同表明在同一個集合,否則不在。
  3. 將兩個集合歸并成一個集合 --將兩個集合中的元素合并將一個集合名稱改成另一個集合的名稱
  4. 集合的個數 --遍歷數組,數組中元素為負數的個數即為集合的個數。

1、省份的數量

本題通過把同一省份的城市放在同一集合中,遍歷所有城市鏈接情況,最后統計出省份(集合)的總數。
在這里插入圖片描述
在這里插入圖片描述
示例代碼:

class UnionFindSet
{
public://根據并查集規則,初始化為-1UnionFindSet(int size):_ufs(size,-1){}//把兩個集合【隊伍】合并void Union(int x1,int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2)return;_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//找到一個元素所在的集合int FindRoot(int x){int parents = x;while (_ufs[parents] >= 0)parents = _ufs[parents];return parents;}//判斷兩個元素是否在同一個集合bool InSameSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}//返回集合的個數size_t Size(){size_t size = 0;for (int i = 0; i < _ufs.size(); ++i){if (_ufs[i] < 0)size++;}return size;}
private:std::vector<int> _ufs;
};
class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {UnionFindSet ufs(isConnected.size());for(int i = 0;i < isConnected.size();++i){for(int j = 0;j < isConnected[i].size();++j){if(isConnected[i][j] == 1)ufs.Union(i,j);}}return ufs.Size();}
};

但是每次都手撕一個并查集,還是麻煩,那就面向過程的來維護并查集ufs,代碼如下:

class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {vector<int> ufs(isConnected.size(),-1);auto findroot = [&ufs](int x){while(ufs[x] >= 0) x = ufs[x]; return x;};for(int i = 0;i < isConnected.size();++i){for(int j = 0;j < isConnected[i].size();++j){if(isConnected[i][j] == 1){int rooti = findroot(i);int rootj = findroot(j);if(rooti == rootj)continue;else{ufs[rooti] += ufs[rootj];ufs[rootj] = rooti;}}}}int ret = 0;for(int i = 0;i < ufs.size();++i)if(ufs[i] < 0)++ret;return ret;}
};

2、等式方程的可滿足性

分兩遍:
第一遍設置集合關系,哪一個元素屬于哪一個集合先劃分好;
第二遍查找相悖,有相悖,返回false;否則true。

在這里插入圖片描述

在這里插入圖片描述

class Solution {
public:bool equationsPossible(vector<string>& equations) {vector<int> ufs(26,-1);auto findroot = [&ufs](int x){while(ufs[x] >= 0)x = ufs[x];return x;};//第一遍先設置集合關系for(int i = 0;i < equations.size();++i){if(equations[i][1] == '='){int root1 = findroot(equations[i][0] - 'a');int root2 = findroot(equations[i][3] - 'a');if(root1 != root2){ufs[root1] += ufs[root2];ufs[root2] = root1;}}}//第二次再查找相悖關系for(int i = 0;i < equations.size();++i){if(equations[i][1] == '!'){int root1 = findroot(equations[i][0] - 'a');int root2 = findroot(equations[i][3] - 'a');if(root1 == root2){return false;}}}//沒有相悖返回真return true;}
};

四、并查集的路徑壓縮

隨著一棵樹的高度增加,并查集的查找效率逐漸降低。路徑壓縮目的是減小樹的高度,進而提高并查集查找效率。
路徑壓縮一般來說有兩種思路:
**第一種:**每次查找一個位置,吧一個節點的位置直接更新到根。
**第二種:**每查找一個位置,把查找路徑上的節點位置都更新到根。

到這里并查集結束了,并查集是為了給圖做鋪墊。


完~
轉載請注明出處

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80702.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80702.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80702.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何快速入門大模型?

學習大模型的流程是什么 &#xff1f; 提示詞工程&#xff1a;只需掌握提問技巧即可使用大模型&#xff0c;通過優化提問方式獲得更精準的模型輸出套殼應用開發&#xff1a;在大模型生態上開發業務層產品&#xff08;如AI主播、AI小助手等&#xff09;&#xff0c;只需調用API…

《AI大模型應知應會100篇》第59篇:Flowise:無代碼搭建大模型應用

第59篇&#xff1a;Flowise&#xff1a;無代碼搭建大模型應用 摘要&#xff1a;本文將詳細探討 Flowise 無代碼平臺的核心特性、使用方法和最佳實踐&#xff0c;提供從安裝到部署的全流程指南&#xff0c;幫助開發者和非技術用戶快速構建復雜的大模型應用。文章結合實戰案例與配…

python打卡day23@浙大疏錦行

知識回顧: 1. 轉化器和估計器的概念 2. 管道工程 3. ColumnTransformer和Pipeline類 作業&#xff1a; 整理下全部邏輯的先后順序&#xff0c;看看能不能制作出適合所有機器學習的通用pipeline 一、導入數據庫 import pandas as pd import numpy as np import matplo…

Vue.js框架的優缺點

別再讓才華被埋沒&#xff0c;別再讓github 項目蒙塵&#xff01;github star 請點擊 GitHub 在線專業服務直通車GitHub賦能精靈 - 艾米莉&#xff0c;立即加入這場席卷全球開發者的星光革命&#xff01;若你有快速提升github Star github 加星數的需求&#xff0c;訪問taimili…

交易流水表的分庫分表設計

交易流水表的分庫分表設計需要結合業務特點、數據增長趨勢和查詢模式&#xff0c;以下是常見的分庫分表策略及實施建議&#xff1a; 一、分庫分表核心目標 解決性能瓶頸&#xff1a;應對高并發寫入和查詢壓力。數據均衡分布&#xff1a;避免單庫/單表數據傾斜。簡化運維&#…

操作系統學習筆記第3章 (竟成)

第 3 章 內存管理 【考綱內容】 1.內存管理基礎&#xff1a; 1.內存管理的基本概念&#xff1a;邏輯地址空間與物理地址空間&#xff1b;地址變換&#xff1b;內存共享&#xff1b;內存保護&#xff1b;內存分配與回收&#xff1b; 2.連續分配管理方式&#xff1b; 3.頁式管理&…

中科院無人機導航物流配送的智能變革!LogisticsVLN:基于無人機視覺語言導航的低空終端配送系統

作者&#xff1a;Xinyuan Zhang, Yonglin Tian, Fei Lin, Yue Liu, Jing Ma, Kornlia Sra Szatmry, Fei-Yue Wang 單位&#xff1a;中國科學院大學人工智能學院&#xff0c;中科院自動化研究所多模態人工智能系統國家重點實驗室&#xff0c;澳門科技大學創新工程學院工程科學系…

1.10-數據傳輸格式

1.10-數據傳輸格式 在對網站進行滲透測試時&#xff0c;使用目標服務器規定的數據傳輸格式來進行 payload 測試非常關鍵 如果不按規定格式發送數據&#xff0c;服務器可能直接拒絕請求或返回錯誤響應&#xff0c;比如&#xff1a; 接口要求 JSON 格式&#xff0c;而你用的是…

dfs 第一次加訓 詳解 下

目錄 P1706 全排列問題 思路 B3618 尋找團伙 思路 B3621 枚舉元組 思路 B3622 枚舉子集&#xff08;遞歸實現指數型枚舉&#xff09; 思路 B3623 枚舉排列&#xff08;遞歸實現排列型枚舉&#xff09; B3625 迷宮尋路 思路 P6183 [USACO10MAR] The Rock Game S 總結…

通信網絡編程——JAVA

1.計算機網絡 IP 定義與作用 &#xff1a;IP 地址是在網絡中用于標識設備的數字標簽&#xff0c;它允許網絡中的設備之間相互定位和通信。每一個設備在特定網絡環境下都有一個唯一的 IP 地址&#xff0c;以此來確定其在網絡中的位置。 分類 &#xff1a;常見的 IP 地址分為 I…

#在 CentOS 7 中手動編譯安裝軟件操作及原理

在 CentOS 7 中&#xff0c;手動編譯安裝軟件&#xff08;即從源代碼編譯安裝&#xff09;是一種高度靈活的方式&#xff0c;適用于需要定制化軟件功能、優化性能或安裝官方倉庫未提供的軟件版本的場景。以下是針對手動編譯安裝的詳細說明&#xff0c;包括原理、步驟、注意事項…

菊廠0510面試手撕題目解答

題目 輸入一個整數數組&#xff0c;返回該數組中最小差出現的次數。 示例1&#xff1a;輸入&#xff1a;[1,3,7,5,9,12]&#xff0c;輸出&#xff1a;4&#xff0c;最小差為2&#xff0c;共出現4次&#xff1b; 示例2&#xff1a;輸入&#xff1a;[90,98,90,90,1,1]&#xf…

C——五子棋小游戲

前言 五子棋&#xff0c;又稱連珠棋&#xff0c;是一種雙人對弈的棋類游戲。游戲目標是在一個棋盤上&#xff0c;通過在橫、豎、斜線上依次放置棋子&#xff0c;使自己的五個棋子連成一線&#xff0c;即橫線、豎線或斜線&#xff0c;且無被對手堵住的空位&#xff0c;從而獲勝…

ik 分詞器 設置自定義詞典

進入 ES 的安裝目錄&#xff0c;進入 /elasticsearch-8.10.0/plugins/ik/config/ 文件夾目錄&#xff0c;打開 IKAnalyzer.cfg.xml 文件進行配置。 一、添加 自定義擴展詞典 擴展詞&#xff1a;就是不想哪些詞分開&#xff0c;讓他們成為一個詞&#xff0c;比如“蒙的全是對…

Linux筆記---信號(上)

1. 信號的概念 Linux下的信號機制是一種進程間通信&#xff08;IPC&#xff09;的方式&#xff0c;用于在不同進程之間傳遞信息。 信號是一種異步的信息傳遞方式&#xff0c;這意味著發送信號的進程只發送由信號作為載體的命令&#xff0c;而并不關心接收信號的進程如何處置這…

UG 二次開發- UG內部調用DLL

【1】用VS新建一個dll工程 將項目設置為x64平臺&#xff08;這步很重要&#xff0c;否則程序無法編譯成功&#xff09; 【2】添加UG頭文件目錄&#xff0c;屬性頁->C/C->常規->附加包含目錄 【3】添加UG庫所在目錄&#xff0c;屬性頁->鏈接器->常規->附加庫目…

wordcount在mapreduce的例子

1.啟動集群 2.創建項目 項目結構為&#xff1a; 3.pom.xml文件為 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://mave…

智慧城市綜合運營管理系統Axure原型

這款Axure原型的設計理念緊緊圍繞城市管理者的需求展開。它旨在打破傳統城市管理中信息孤島的局面&#xff0c;通過統一標準接入各類業務系統&#xff0c;實現城市運營管理信息資源的全面整合與共享。以城市管理者為中心&#xff0c;為其提供一個直觀、便捷、高效的協同服務平臺…

Go語言:json 作用和語法

在 Go 語言中&#xff0c;JSON 字段&#xff08;也稱為 JSON Tag&#xff09;是附加在結構體字段上的元數據&#xff0c;用于控制該字段在 JSON 編碼&#xff08;序列化&#xff09;和解碼&#xff08;反序列化&#xff09; 時的行為。它的語法是&#xff1a; type StructName…

MATLAB復制Excel數據到指定區域

Matlab中如何將Excel表中的265-528行F-AA列數據復制到1-263行AE-AZ中 版本&#xff1a;MatlabR2018b clc; clear; %舊Excel文件名 oldFile ; %新Excel文件名 newFile ; % 工作表名稱&#xff08;舊表和新表一致&#xff09; sheetName Sheet1; % 舊文件中待復制的數據范…