DS并查集(17)

文章目錄

  • 前言
  • 一、何為并查集?
  • 二、并查集的實現?
    • 并查集的初始化
    • 查找元素所在的集合
    • 判斷兩個元素是否在同一個集合
    • 合并兩個元素所在的集合
    • 獲取并查集中集合的個數
    • 并查集的路徑壓縮
  • 三、來兩道題練練手?
    • 省份的數量
    • 等式方程的可滿足性
  • 總結


前言

??其實我一開始是想直接講圖的,但是但是考慮的圖的 Kruskal 算法要用到,就先講解下并查集吧!


一、何為并查集?

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

這可能太抽象了,我們舉個具體的例子:

??以朋友圈為例,現在有10個人(從0開始編號),剛開始這10個人互不認識,所以各自屬于一個集合
在這里插入圖片描述
??并查集會用一個數組來表示這10個人之間的關系,數組的下標對應就是這10個人的編號,剛開始時數組中的元素都初始化為-1
在這里插入圖片描述

數組中某個位置的值為負數,表示該位置是樹的根,這個負數的絕對值表示的這棵樹(集合)中數據的個數,因為剛開始每個人各自屬于一個集合,所以將數組中的位置都初始化為-1

??后來這10個人之間通過相互認識,最終形成了三個朋友圈
在這里插入圖片描述
??此時并查集數組中各個位置的值如下
在這里插入圖片描述

數組中某個位置的值為非負數,表示該位置不是樹的根,這個非負數的值就是這個結點的父結點的編號

??后來4號和8號又通過某種機遇互相認識了,這時他們所在的兩個集合就需要進行合并,最終就變成了兩個朋友圈

在這里插入圖片描述
??需要注意的是,在根據兩個元素合并兩個集合時,需要先分別找到這兩個元素所在集合的根結點,然后再將一個集合合并到另一個集合,并且合并后需要更新數組中根結點的值

在這里插入圖片描述

為什么要找根節點?

  1. 如果這兩個元素所在集合的根結點相同,說明這兩個元素本身就在同一個集合,無需合并
  2. 合并集合后需要更新這兩個集合的根結點的值

??而要判斷兩個元素是否在同一個集合,也就是判斷這兩個元素所在集合的根結點是否相同

二、并查集的實現?

??首先我們要想元素的下標是否對應,如果無法對應的話,我們一般利用容器 map 來存儲元素的下標映射

template<class T>
class UnionFindSet
{
public:UnionFindSet(const T* a, size_t n){for (size_t i = 0 ; i < n ; i++) {_a.push_back(a[i]);_indexMap[a[i]] = i;}}
private:vector<T> _a; // 編號找人map<T, int> _indexMap;// 人找編號
};

??不過在這里,我們假設給的就是下標,也就是說私有成員就只有一個 vector< int > _ufs

并查集的初始化

??并查集中會用一個數組來維護各個結點之間的關系,在初始化并查集時,根據元素的個數開辟數組空間,并將數組中的元素初始化為 -1 即可

//構造函數
UnionFindSet(int n):_ufs(n, -1) //初始時各個元素自成一個集合
{}

查找元素所在的集合

查找邏輯如下:

  • 如果元素對應下標位置存儲的是負數,則說明該元素即為根結點,返回該元素即可。
  • 如果元素對應下標位置存儲的是非負數,則跳轉到其父結點的位置繼續查找根結點。
    int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}return root;}

判斷兩個元素是否在同一個集合

    bool isInset(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}

合并兩個元素所在的集合

合并邏輯如下:

  • 分別找到兩個元素所在集合的根結點。
  • 如果這兩個元素所在集合的根結點相同,則無需合并,如果這兩個元素所在集合的根結點不同,則將小集合合并到大集合上。
  • 將小集合根結點的值累加到大集合的根結點上,使得大集合根結點的值的絕對值等于兩個集合中元素的總數。
  • 將小集合根結點的值改為大集合根結點的編號,也就是讓小集合的根結點作為大集合根結點的孩子,使得兩個集合變為一個集合。
    // 合并兩個集合void Union(int x1, int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);// 如果本身就在一個集合,那么無需合并if (root1 == root2) return ;// 合并的時候,作為孩子,其深度會增加一層// 因此,理論上來說,數據量小的作孩子// 如果有需求下標小的作根,則交換一下root// if (root1 > root2) swap(root1, root2); // 按照下標大小if (abs(_ufs[root1]) < abs(_ufs[root2])) swap(root1, root2); // 按照數據量大小// 如果不在同一個集合,則默認認為把x2代表集合合并到x1上,即x1作根,x2作子_ufs[root1] += _ufs[root2];// 將x2代表集合的名稱改為x1_ufs[root2] = root1;}

獲取并查集中集合的個數

??要獲取并查集中集合的個數,本質就是統計數組中負值(根結點)的個數

    size_t SetSize(){size_t size = 0;for (size_t i = 0 ; i < _ufs.size() ; i++){if (_ufs[i] < 0) size++;}return size;}

并查集的路徑壓縮

??當數據量很大的時候,并查集中樹的層數可能會變得很高,這時再查找一個元素所在集合的根結點時就需要往上走很多層,這時可以考慮進行路徑壓縮

??路徑壓縮一般會在查找根結點時進行,當根據一個結點查找其根結點時,該路徑上所有的結點都會被壓縮,最終這些結點會直接被掛在根結點下,下次再根據這些結點查找根結點時就能快速找到根結點

    int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}// 路徑壓縮,用于應對深度太深的情況// 把路徑上所有節點都作為根的孩子while (_ufs[x] >= 0){int parent = _ufs[x];_ufs[x] = root;x = parent;}return root;}

三、來兩道題練練手?

省份的數量

LCR 116. 省份數量

在這里插入圖片描述
思路其實是很明確的:

  1. 定義一個長度為 n 的數組充當并查集,并將數組中的元素初始化為 -1,表示各個城市各自是一個省份。
  2. 根據所給矩陣,對并查集中的各個集合進行合并。
  3. 并查集中集合的個數即為省份的數量
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]){ufs.Union(i, j);}}}return ufs.SetSize();}};

等式方程的可滿足性

990. 等式方程的可滿足性

在這里插入圖片描述
思路其實也是很明確的:

  1. 定義一個長度為26(變量為小寫字母)的數組充當并查集,并將數組中的元素初始化為-1,表示各個字母只有自己等于自己。
  2. 根據字符串方程組中的等式,對并查集中的各個集合進行合并(每個集合中的元素都是相等的)。
  3. 根據并查集,對字符串方程組中的不等式進行驗證,如果兩個不相等的變量出現在同一個集合中,則返回 false 。
class Solution
{
public:bool equationsPossible(vector<string>& equations){UnionFindSet ufs(26);for (const auto& str : equations){if (str[1] == '='){ufs.Union(str[0] - 'a', str[3] - 'a');}}for (const auto& str : equations){if (str[1] == '!'){int root1 = ufs.FindRoot(str[0] - 'a');int root2 = ufs.FindRoot(str[3] - 'a');if (root1 == root2) return false;}}return true;}
};

總結

??其實,從這里開始的數據結構就比較困難了
??圖、跳表、B樹,它們要來了!!!

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

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

相關文章

Appium介紹

在使用不同版本的Appium包進行自動化測試時&#xff0c;出現警告問題可能是由于版本不兼容、配置不正確等原因導致的。下面將詳細介紹解決這些問題的步驟&#xff0c;確保模擬器能夠正常啟動&#xff0c;并能在Appium查看器中同步顯示。 1. 環境準備 首先&#xff0c;確保你已…

minimind - 從零開始訓練小型語言模型

大語言模型&#xff08;LLM&#xff09;領域&#xff0c;如 GPT、LLaMA、GLM 等&#xff0c;雖然它們效果驚艷&#xff0c; 但動輒10 Bilion龐大的模型參數個人設備顯存遠不夠訓練&#xff0c;甚至推理困難。 幾乎所有人都不會只滿足于用Lora等方案fine-tuing大模型學會一些新的…

【C++動態規劃 離散化】1626. 無矛盾的最佳球隊|2027

本文涉及知識點 C動態規劃 離散化 LeetCode1626. 無矛盾的最佳球隊 假設你是球隊的經理。對于即將到來的錦標賽&#xff0c;你想組合一支總體得分最高的球隊。球隊的得分是球隊中所有球員的分數 總和 。 然而&#xff0c;球隊中的矛盾會限制球員的發揮&#xff0c;所以必須選…

CSS 值和單位詳解:從基礎到實戰

CSS 值和單位詳解&#xff1a;從基礎到實戰 1. 什么是 CSS 的值&#xff1f;示例代碼&#xff1a;使用顏色關鍵字和 RGB 函數 2. 數字、長度和百分比2.1 長度單位絕對長度單位相對長度單位 2.2 百分比 3. 顏色3.1 顏色關鍵字3.2 十六進制 RGB 值3.3 RGB 和 RGBA 值3.4 HSL 和 H…

Privacy Eraser,電腦隱私的終極清除者

Privacy Eraser 是一款專為保護用戶隱私而設計的全能型軟件&#xff0c;它不僅能夠深度清理計算機中的各類隱私數據&#xff0c;還提供了多種系統優化工具&#xff0c;幫助用戶提升設備的整體性能。通過這款軟件&#xff0c;用戶可以輕松清除瀏覽器歷史記錄、緩存文件、Cookie、…

Android 啟動流程

一 Bootloader 階段 在嵌入式系統中&#xff0c;Bootloader的引導過程與傳統的PC環境有所不同&#xff0c;主要是因為嵌入式系統的硬件配置和應用場景更加多樣化。以下是嵌入式系統中Bootloader被引導的一般流程&#xff1a; 1. 硬件復位 當嵌入式設備上電或復位時&#xff…

【數據結構與算法】AVL樹的插入與刪除實現詳解

文章目錄 前言Ⅰ. AVL樹的定義Ⅱ. AVL樹節點的定義Ⅲ. AVL樹的插入Insert一、節點的插入二、插入的旋轉① 新節點插入較高左子樹的左側&#xff08;左左&#xff09;&#xff1a;右單旋② 新節點插入較高右子樹的右側&#xff08;右右&#xff09;&#xff1a;左單旋③ 新節點插…

SCRM開發為企業提供全面客戶管理解決方案與創新實踐分享

內容概要 在當今的商業環境中&#xff0c;客戶關系管理&#xff08;CRM&#xff09;變得越來越重要。而SCRM&#xff08;社交客戶關系管理&#xff09;作為一種新興的解決方案&#xff0c;正在幫助企業徹底改變與客戶的互動方式。快鯨SCRM是一個引人注目的工具&#xff0c;它通…

AI應用部署——streamlit

如何把項目部署到一個具有公網ip地址的服務器上&#xff0c;讓他人看到&#xff1f; 可以利用 streamlit 的社區云免費部署 1、生成requirements.txt文件 終端輸入pip freeze > requirements.txt即可 requirements.txt里既包括自己安裝過的庫&#xff0c;也包括這些庫的…

【C/C++】區分0、NULL和nullptr

&#x1f984;個人主頁:小米里的大麥-CSDN博客 &#x1f38f;所屬專欄:C_小米里的大麥的博客-CSDN博客 &#x1f381;代碼托管:C: 探索C編程精髓&#xff0c;打造高效代碼倉庫 (gitee.com) ??操作環境:Visual Studio 2022 目錄 1. 0 和空指針 2. NULL 3. nullptr 總結 …

【Numpy核心編程攻略:Python數據處理、分析詳解與科學計算】2.1 NumPy高級索引:布爾型與花式索引的底層原理

2.1 NumPy高級索引&#xff1a;布爾型與花式索引的底層原理 目錄 #mermaid-svg-NpcC75NxxU2mkB3V {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NpcC75NxxU2mkB3V .error-icon{fill:#552222;}#mermaid-svg-NpcC75…

云原生(五十二) | DataGrip軟件使用

文章目錄 DataGrip軟件使用 一、DataGrip基本使用 二、軟件界面介紹 三、附件文件夾到項目中 四、DataGrip設置 五、SQL執行快捷鍵 DataGrip軟件使用 一、DataGrip基本使用 1. 軟件界面介紹 2. 附加文件夾到項目中【重要】 3. DataGrip配置 快捷鍵使用&#xff1a;C…

【Elasticsearch】match_bool_prefix 查詢 vs match_phrase_prefix 查詢

Match Bool Prefix Query vs. Match Phrase Prefix Query 在 Elasticsearch 中&#xff0c;match_bool_prefix 查詢和 match_phrase_prefix 查詢雖然都支持前綴匹配&#xff0c;但它們的行為和用途有所不同。以下是它們之間的主要區別&#xff1a; 1. match_bool_prefix 查詢…

算法基礎——存儲

引入 基礎理論的進步&#xff0c;是推動技術實現重大突破&#xff0c;促使相關領域的技術達成跨越式發展的核心。 在發展日新月異的大數據領域&#xff0c;基礎理論的核心無疑是算法。不管是技術設計&#xff0c;還是工程實踐&#xff0c;都必須仰仗相關算法的支持&#xff0…

正則表達式入門

入門 1、提取文章中所有的英文單詞 //1&#xff0e;先創建一個Pattern對象&#xff0c;模式對象&#xff0c;可以理解成就是一個正則表達式對象 Pattern pattern Pattern.compile("[a-zA-Z]"); //2&#xff0e;創建一個匹配器對象 //理解:就是 matcher匹配器按照p…

分布式架構中的事務管理:需要了解的常見解決方案

前言 在現代互聯網應用中&#xff0c;分布式架構越來越常見。隨著系統規模的擴大&#xff0c;越來越多的業務和數據被分布到不同的服務和數據庫中。雖然分布式架構帶來了諸多優勢&#xff0c;但也引入了一個新的問題&#xff1a;分布式事務。 一、什么是分布式事務&#xff1…

《TCP 網絡編程實戰:開發流程、緩沖區原理、三次握手與四次揮手》

一、 TCP 網絡應用程序開發流程 學習目標 能夠知道TCP客戶端程序的開發流程1. TCP 網絡應用程序開發流程的介紹 TCP 網絡應用程序開發分為: TCP 客戶端程序開發TCP 服務端程序開發說明: 客戶端程序是指運行在用戶設備上的程序 服務端程序是指運行在服務器設備上的程序,專門…

新年新挑戰:如何用LabVIEW開發跨平臺應用

新的一年往往伴隨著各種新的項目需求&#xff0c;而跨平臺應用開發無疑是當前備受矚目的發展趨勢。在眾多開發工具中&#xff0c;LabVIEW 以其獨特的圖形化編程方式和強大的功能&#xff0c;為開發跨平臺應用提供了有效的途徑。本文將深入探討如何運用 LabVIEW 開發能夠在不同操…

C 語言實現計算一年中指定日期是第幾天?題】

引言 在編程的世界里&#xff0c;處理日期和時間相關的問題是非常常見的。比如在日歷應用、任務管理系統、數據分析等場景中&#xff0c;經常需要計算某個日期在一年中是第幾天。本文將詳細介紹如何使用 C 語言來實現這一功能&#xff0c;通過分析代碼的結構、邏輯以及可能存在…

rsync安裝與使用-linux015

使用 rsync 可以非常高效地將文件或目錄從一個服務器傳輸到另一個服務器。 能力&#xff1a; 支持 64 位文件、64 位 inode、64 位時間戳、64 位長整型支持套接字對、符號鏈接、符號鏈接時間、硬鏈接、硬鏈接特殊文件、硬鏈接符號鏈接支持 IPv6、訪問時間&#xff08;atimes&…