其它高階數據結構①_并查集(概念+代碼+兩道OJ)

目錄

1. 并查集的概念

2. 并查集的實現

3. 并查集的應用

3.1 力扣LCR 116. 省份數量

解析代碼1

解析代碼2

3.2 力扣990. 等式方程的可滿足性

解析代碼

本篇完。


寫在前面:

????????此高階數據結構系列,雖然放在⑤數據結構與算法專欄,但還是作為一個拓展學習,建議跳過第⑤序號跟著其它專欄序號學,當時是想著要期末考和考研的同學,考到圖才開這個專欄的吧,其他不急的同學可以在學完MySQL專欄后再看,此系列也放在了⑩其它高階數據結構專欄,這里簡單學習并查集是為了下一個數據結構“圖”的學習。


1. 并查集的概念

  • 并查集是一種樹型的數據結構,用于處理一些不相交集合的合并及查詢問題。
  • 并查集通常用森林來表示,森林中的每棵樹表示一個集合,樹中的結點對應一個元素。

????????雖然利用其它數據結構也能完成不相交集合的合并及查詢,但在數據量極大的情況下,其耗費的時間和空間也是極大的。

????????在一些應用問題中,需要將n個不同的元素劃分成一些不相交的集合。開始時,每個元素自成一個單元素集合,然后按一定的規律將歸于同一組元素的集合合并。在此過程中要反復用到查詢某一 個元素歸屬于那個集合的運算。適合于描述這類問題的抽象數據類型稱為并查集(union-find set)。

????????并查集是多個獨立集合的合集,用于表示數據之間的關系,并查集中的每一個集合是用多叉樹來表示的。

????????比如:某公司今年校招全國總共招生10人,西安招4人,成都招3人,武漢招3人,10個人來自不 同的學校,起先互不相識,每個學生都是一個獨立的小團體,現給這些學生進行編號:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 給以下數組用來存儲該小集體,數組中的數字代表:該小集體中具有成員的個 數。數組中某個位置的值為負數,表示該位置是樹的根,這個負數的絕對值表示的這棵樹(集合)中數據的個數,因為剛開始每個人各自屬于一個集合,所以將數組中的位置都初始化為-1。

????????畢業后,學生們要去公司上班,每個地方的學生自發組織成小分隊一起上路,于是:西安學生小分隊s1={0,6,7,8},成都學生小分隊s2={1,4,9},武漢學生小分隊s3={2,3,5}就相互認識了,10個人形成了三個小團體。假設右三個群主0,1,2擔任隊長,負責大家的出行。

一趟火車之旅后,每個小分隊成員就互相熟悉,稱為了一個朋友圈。

????????從上圖可以看出:編號6,7,8同學屬于0號小分隊,該小分隊中有4人(包含隊長0);編號為4和9的同 學屬于1號小分隊,該小分隊有3人(包含隊長1),編號為3和5的同學屬于2號小分隊,該小分隊有3 個人(包含隊長1)。 仔細觀察數組中內變化,可以得出以下結論:

  1. 數組的下標對應集合中元素的編號。
  2. 數組中如果為負數,負號代表根,數字代表該集合中元素個數。
  3. 數組中如果為非負數,代表該元素雙親在數組中的下標。

????????在公司工作一段時間后,西安小分隊中8號同學與成都小分隊1號同學奇跡般的走到了一起,兩個小圈子的學生相互介紹,最后成為了一個小圈子:

????????現在0集合有7個人,2集合有3個人,總共兩個朋友圈。通過以上例子可知,并查集一般可以解決一下問題:

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

2. 并查集的實現

代碼實現還是很簡單的,直接放出代碼:(建議復制到自己編譯器跟著注釋一起看)

#pragma once#include <iostream>
#include <vector>
using namespace std;class UnionFindSet
{
private:vector<int> _ufs;public:UnionFindSet(size_t size) // 初始時,將數組中元素全部設置為1: _ufs(size, -1){}int FindRoot(int index) // 給一個元素的編號,找到該元素所在集合的名稱{int root = index;while (_ufs[root] >= 0)   // 如果數組中存儲的是負數,找到,否則一直繼續{root = _ufs[root];}while (_ufs[index] >= 0) // 路徑壓縮{int parent = _ufs[index];_ufs[index] = root;index = parent;}return index;}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}bool Union(int x1, int x2) // 合并兩個集合{int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2) // x1已經與x2在同一個集合return false;if (abs(_ufs[root1]) < abs(_ufs[root2])) // 控制數據量小的往大的集合合并swap(root1, root2);_ufs[root1] += _ufs[root2]; // 負號代表根,數字代表該集合中元素個數_ufs[root2] = root1; // 將其中一個集合名稱改變成另外一個return true;}size_t Count() const  // 數組中負數的個數,即為集合的個數{size_t count = 0;for (auto e : _ufs){if (e < 0)++count;}return count;}
};void TestUFS()
{UnionFindSet u(10);u.Union(0, 6);u.Union(7, 6);u.Union(7, 8);u.Union(1, 4);u.Union(4, 9);u.Union(2, 3);u.Union(2, 5);u.FindRoot(6);u.FindRoot(9);cout << u.Count() << endl;
}


3. 并查集的應用

直接復制上面并查集的代碼到力扣寫兩道題:

3.1 力扣LCR 116. 省份數量

LCR 116. 省份數量

難度 中等

有?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]

注意:本題與主站 547?題相同:?547. 省份數量

class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {}
};

解析代碼1

直接復制并查集過來:

class UnionFindSet
{
private:vector<int> _ufs;public:UnionFindSet(size_t size) // 初始時,將數組中元素全部設置為1: _ufs(size, -1){}int FindRoot(int index) // 給一個元素的編號,找到該元素所在集合的名稱{int root = index;while (_ufs[root] >= 0)   // 如果數組中存儲的是負數,找到,否則一直繼續{root = _ufs[root];}while (_ufs[index] >= 0) // 路徑壓縮{int parent = _ufs[index];_ufs[index] = root;index = parent;}return index;}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}bool Union(int x1, int x2) // 合并兩個集合{int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2) // x1已經與x2在同一個集合return false;if (abs(_ufs[root1]) < abs(_ufs[root2])) // 控制數據量小的往大的集合合并swap(root1, root2);_ufs[root1] += _ufs[root2]; // 負號代表根,數字代表該集合中元素個數_ufs[root2] = root1; // 將其中一個集合名稱改變成另外一個return true;}size_t Count() const  // 數組中負數的個數,即為集合的個數{size_t count = 0;for (auto e : _ufs){if (e < 0)++count;}return count;}
};class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {UnionFindSet ufs(isConnected.size());for (size_t i = 0; i < isConnected.size(); ++i){for (size_t j = 0; j < isConnected[i].size(); ++j){if (isConnected[i][j] == 1) // 合并集合{ufs.Union(i, j);}}}return ufs.Count();}
};


解析代碼2

用數組模擬并查集:

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(size_t i = 0; i < isConnected.size(); ++i){for(size_t j = 0; j < isConnected[i].size(); ++j){if(isConnected[i][j] == 1) // 合并集合{int root1 = findRoot(i);int root2 = findRoot(j);if (root1 != root2){ufs[root1] += ufs[root2];ufs[root2] = root1;}}}}int cnt = 0;for(auto e : ufs){if(e < 0)++cnt;}return cnt;}
};


3.2 力扣990. 等式方程的可滿足性

990. 等式方程的可滿足性

難度 中等

給定一個由表示變量之間關系的字符串方程組成的數組,每個字符串方程?equations[i]?的長度為?4,并采用兩種不同的形式之一:"a==b"?或?"a!=b"。在這里,a 和 b 是小寫字母(不一定不同),表示單字母變量名。

只有當可以將整數分配給變量名,以便滿足所有給定的方程時才返回?true,否則返回?false。?

示例 1:

輸入:["a==b","b!=a"]
輸出:false
解釋:如果我們指定,a = 1 且 b = 1,那么可以滿足第一個方程,但無法滿足第二個方程。沒有辦法分配變量同時滿足這兩個方程。

示例 2:

輸入:["b==a","a==b"]
輸出:true
解釋:我們可以指定 a = 1 且 b = 1 以滿足滿足這兩個方程。

示例 3:

輸入:["a==b","b==c","a==c"]
輸出:true

示例 4:

輸入:["a==b","b!=c","c==a"]
輸出:false

示例 5:

輸入:["c==c","b==d","x!=z"]
輸出:true

提示:

  1. 1 <= equations.length <= 500
  2. equations[i].length == 4
  3. equations[i][0]?和?equations[i][3]?是小寫字母
  4. equations[i][1]?要么是?'=',要么是?'!'
  5. equations[i][2]?是?'='
class Solution {
public:bool equationsPossible(vector<string>& equations) {}
};

解析代碼

并查集的變形,思路:

  1. 將所有"=="兩端的字符合并到一個集合中。
  2. 檢測"!=" 兩端的字符是否在同一個集合中,如果在,不滿足,如果不在,滿足。
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(auto& e : equations) // 第一遍,先把相等的值加到一個集合中{if(e[1] == '='){int root1 = findRoot(e[0] - 'a');int root2 = findRoot(e[3] - 'a');if(root1 != root2){ufs[root1] += ufs[root2];ufs[root2] = root1;}}}for(auto& e : equations) // 第二遍,判斷相等在不在一個集合,在就相悖了{if(e[1] == '!'){int root1 = findRoot(e[0] - 'a');int root2 = findRoot(e[3] - 'a');if(root1 == root2)return false;}}return true;}
};


本篇完。

這里簡單學習并查集更多是為了下一個數據結構“圖”的學習,一些競賽的OJ也會用到并查集。

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

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

相關文章

【數據可視化01】matplotlib實例介紹4之六邊形分箱圖

目錄 一、引言二、實例介紹 一、引言 hexbin是一個二維直方圖&#xff0c;其中箱子是六邊形&#xff0c;顏色表示每個箱子內的數據點數。 二、實例介紹 import matplotlib.pyplot as plt import numpy as np# Fixing random state for reproducibility np.random.seed(19680…

服務器利用率的神器腳本

在服務器管理的過程中&#xff0c;了解服務器的各項性能指標是至關重要的。無論是CPU的負載情況&#xff0c;內存使用情況&#xff0c;還是硬盤的存儲空間以及TCP連接狀態&#xff0c;這些都是我們判斷服務器健康狀態和性能的重要依據。然而&#xff0c;手動一項項去檢查這些指…

【MySQL】Mysql——安裝指南(Linux)

MySQL8.0.26-Linux版安裝 1. 準備一臺Linux服務器 云服務器或者虛擬機都可以; Linux的版本為 CentOS7; 2. 下載Linux版MySQL安裝包 3. 上傳MySQL安裝包 4. 創建目錄,并解壓 mkdir mysqltar -xvf mysql-8.0.26-1.el7.x86_64.rpm-bundle.tar -C mysql5. 安裝mysql的安裝包 …

pip鏡像源

1.1 清華大學 https://pypi.tuna.tsinghua.edu.cn/simple 1.2 阿里云 https://mirrors.aliyun.com/pypi/simple/ 1.3 網易 https://mirrors.163.com/pypi/simple/ 1.4 豆瓣 https://pypi.douban.com/simple/ 1.5 百度云 https://mirror.baidu.com/pypi/simple/ 1.6 中科大 ht…

uniapp vue 獲取天氣數據

獲取當前地址&#xff0c;通過高德天氣數據&#xff0c;來展示天氣溫度風度等數據 //獲取天氣 getWeather(){// 獲取天氣預報uni.request({url: https://restapi.amap.com/v3/weather/weatherInfo, data: {city: 長沙,// extensions:all,key: xxxxxxxxxx//自己的高德密鑰key},…

2024OD機試卷-轉盤壽司 (java\python\c++)

題目:轉盤壽司 題目描述 壽司店周年慶,正在舉辦 優惠活動 回饋新老客戶。 壽司轉盤上總共有 n 盤壽司,prices[i] 是第 i 盤壽司的價格, 如果客戶選擇了第 i 盤壽司,壽司店免費贈送客戶距離第 i 盤壽司最近的下一盤壽司 j,前提是 prices[j] < prices[i],如果沒有滿足…

RAG 面向 LLM: 基于檢索增強的大語言模型調研

摘要 作為 AI 領域最先進的技術之一,檢索增強生成(RAG)技術可以提供可靠和最新的外部知識,為眾多任務提供巨大的便利。特別是在 AI 生成內容(AIGC)時代,RAG 中檢索強大的提供額外知識的能力使得檢索增強生成能夠輔助現有生成式 AI 生產高質量輸出。最近,大語言模型(LLM)在語言…

Zoho CRM企業成長的智能引擎,智能化銷售自動化

數字化時代&#xff0c;客戶體驗已成為企業競爭的核心要素。卓豪Zoho CRM&#xff0c;作為全球領先的SaaS云端客戶關系管理平臺&#xff0c;正引領著一場企業運營模式的變革&#xff0c;助力超過25萬家企業跨越180多個國家&#xff0c;實現客戶互動與業務增長的無縫對接。讓我們…

廣汽原車控制系統CAN協議控制汽車基本信息獲取及數據應用

在現代汽車工業的迅速發展中&#xff0c;車輛控制系統的智能化和網絡化已成為提升汽車性能的關鍵。廣汽作為中國汽車行業的佼佼者&#xff0c;其在原車通信網絡方面也取得了顯著的成就。特別是廣汽原車CAN&#xff08;Controller Area Network&#xff09;協議的應用&#xff0…

2024OD機試卷-分割均衡字符串 (java\python\c++)

題目:分割均衡字符串 題目描述 均衡串定義: 字符串 中只包含兩種字符,且這兩種字符的個數相同。 給定一個均衡字符串,請給出可分割成新的均衡子串的最大個數。 約定:字符串中只包含大寫的 X 和 Y 兩種字符。 輸入描述 字符串的長度:[2, 10000]。 給定的字符串均為均…

添磚Java之路(其六)——通過集合制作的學生信息管理系統

目錄 前言&#xff1a; 源碼&#xff1a; 前言&#xff1a; 我對于集合的理解&#xff0c;感覺就類似于順序表這樣的數據結構&#xff0c;然后他存儲的數據不能是基本類型&#xff0c;如果要用也只能用對應基本數據的包裝類。 對于集合有很多方法&#xff0c;我的建議就是去…

【運維】nvidia-smi錯誤信息:Failed to initialize NVML: Driver/library version mismatch

【運維】錯誤信息&#xff1a;Failed to initialize NVML: Driver/library version mismatch 是因為Nvidia的驅動沖突的原因 本地部署&#xff1a;本地Docker容器部署&#xff0c;本地驗證后打包鏡像 遠程部署&#xff1a;鏡像部署阿里云PAI EAS 因為在容器中安裝了驅動版本&a…

短視頻最后的慢動作怎么做:成都鼎茂宏升文化傳媒公司

短視頻最后的慢動作怎么做&#xff1a;技巧與創意實踐指南 在短視頻創作的浩瀚宇宙中&#xff0c;慢動作特效如同一顆璀璨的星辰&#xff0c;為作品增添無限魅力與情感深度。它不僅能夠放大細節之美&#xff0c;還能延長關鍵瞬間&#xff0c;引發觀眾強烈的情感共鳴。短視頻最…

SpringBoot項目的項目部署全過程

一、前端 安裝nginx 1.將提前準備好的nginx的安裝包上傳到Linux中/opt目錄下(我用的是Xftp) 2.解壓 2.1:在xshell中解壓該文件: tar -zxvf nginx-1.20.1.tar.gz 2.2:進入解壓后的目錄 cd nginx-1.20.1/ 2.3:安裝需要的依賴 yum -y install zlib zlib-devel openssl openssl-de…

html特殊字符的html,js,css寫法匯總

? 箭頭類 符號UNICODE符號UNICODEHTMLJSCSSHTMLJSCSS?&#8672\u21E0\21E0?&#8674\u21E2\21E2?&#8673\u21E1\21E1?&#8675\u21E3\21E3?&#8606\u219E\219E?&#8608\u21A0\21A0?&#8607\u219F\219F?&#8609\u21A1\21A1←&#8592\u2190\2…

FreeRTOS【4】線程掛起和恢復

1.開發背景 基于上一篇指引&#xff0c;成功創建并啟動線程后&#xff0c;線程已經開始運行了&#xff0c;但是有時我們需要線程暫停運行&#xff0c;例如某個線程是控制 LED 閃燈的&#xff0c;如果現在需要讓 LED 停止工作&#xff0c;單純的關閉 LED 是沒用的&#xff0c;因…

Python中json數據的常用操作函數:dump load dumps和loads

文章目錄 dump函數load函數dumps函數loads函數 dump函數 功能&#xff1a;將Python對象序列化為JSON格式的字符串&#xff0c;并寫入到文件中。這個方法用于將數據保存到文件中。語法&#xff1a;json.dump(需要進行json序列化的Python對象, 寫入的文件路徑) load函數 功能&…

文科生在三本院校,讀計算機專業

6歲&#xff0c;進入村小&#xff0c;一年級&#xff0c;老師問我的夢想是什么&#xff0c;我說我長大了我要成為科學家。 9歲&#xff0c;三年級&#xff0c;知道科學家不現實&#xff0c;開始學習英語。又因為科學家英語不好發音&#xff0c;于是我的夢想變了&#xff0c;長…

ZCC5503 18V 1A 6uA低靜態功耗 同步降壓控制器

1. 概要 ZCC5503R 是一款基準電壓源、振蕩電路、 比較器 PWM/PFM 控制器構成的 CMOS 降壓電路調整器&#xff0c;利用 PWM/PFM 自動切換控制電路達到可調占空比&#xff0c;具有全輸入電壓范圍&#xff08;3~18V &#xff09;內的低紋波、高效率及大電流輸出等特點. 2. 產品特性…

【智能優化算法】雁群優化算法(Wild Geese Algorithm,WGA)

雁群優化算法(Wild Geese Algorithm,WGA)是期刊“Array”的2021年智能優化算法 01.引言 雁群優化算法(Wild Geese Algorithm,WGA)用于大規模全局優化&#xff0c;并利用IEEE CEC 2008和CEC 2010高維D100、500、1000特別會議的大規模測試函數驗證了該算法的效率和性能。WGA的靈…