數據結構與算法:圖論——并查集

先給出并查集的模板,還有一些leetcode算法題,以后遇見了相關題目再往上增加

并查集模板

整體模板C++代碼如下:

  • 空間復雜度: O(n) ,申請一個father數組。

  • 時間復雜度

    路徑壓縮后的并查集時間復雜度在O(logn)與O(1)之間,且隨著查詢或者合并操作的增加,時間復雜度會越來越趨于O(1)。

int n = 51000;
vector<int> father = vector<int>(n);
/*
錯誤的方法
class Foo(){
private:vector<string> name(5); //error in these 2 linesvector<int> val(5,0);
}
正確的方法
C++11以后:
class Foo(){
private:vector<string> name = vector<string>(5);vector<int> val{vector<int>(5,0)};
}
*/// 并查集初始化
void init() {for (int i = 0; i < father.size(); i++) {father[i] = i;}
}// 并查集里尋根的過程:路徑壓縮
int find(int a) {if (father[a] == a)return a;elsereturn father[a] = find(father[a]);
}bool same(int a, int b) {a = find(a);b = find(b);return a == b;
}// 將a->b 這條邊加入并查集
void join(int a, int b) {a = find(a);    //找根b = find(b);if (a == b)return;elsefather[a] = b;
}init();

1、1971. 尋找圖中是否存在路徑

在這里插入圖片描述

  • 思路:直接并查集套用即可

提示:

  • 1 <= n <= 2 * 105
  • 0 <= edges.length <= 2 * 105
  • edges[i].length == 2
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 0 <= source, destination <= n - 1
  • 不存在重復邊
  • 不存在指向頂點自身的邊
class Solution {
public:int n = 200001;vector<int> father = vector<int>(n);void init() {for (int i = 0; i < n; i++) {father[i] = i;}}int find(int a) {if (a == father[a])return a;else {return father[a] = find(father[a]);}}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;else {father[a] = b;}}bool validPath(int n, vector<vector<int>>& edges, int source,int destination) {init();for (auto& a : edges) {join(a[0], a[1]);}return find(source) == find(destination);}
};
image-20240509155416437

image-20240509155459673

2、547. 省份數量

在這里插入圖片描述

  • 思路:并查集:再通過set來統計個數

n 個城市,其中一些彼此相連,另一些沒有相連。如果城市 a 與城市 b 直接相連,且城市 b 與城市 c
直接相連,那么城市 a 與城市 c 間接相連。

省份 是一組直接或間接相連的城市,組內不含其他沒有相連的城市。

給你一個 n x n 的矩陣 isConnected ,其中 isConnected[i][j] = 1 表示第 i
個城市和第 j 個城市直接相連,而 isConnected[i][j] = 0 表示二者不直接相連。

返回矩陣中 省份 的數量。

示例 1:

img

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

示例 2:

img

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

提示:

  • 1 <= n <= 200
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][j]10
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]
class Solution {
public:int n = 205;vector<int> father{vector<int>(n)};void init() {for (int i = 0; i < n; i++) {father[i] = i;}}int find(int a) {if (a == father[a])return a;else {return father[a] = find(father[a]);}}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;else {father[a] = b;}}int findCircleNum(vector<vector<int>>& isConnected) {init();int len = isConnected.size();for (int i = 0; i < len; i++) {for (int j = 0; j < len; j++) {if (isConnected[i][j]) {join(i, j);}}}// 統計父節點的個數有兩種方式:// 1、使用set比較直觀:但是復雜度高// unordered_set<int> st;// for (int i = 0; i < len; i++) {//     st.insert(find(i));// }// return st.size();// 2、直接在范圍內統計 father[i] == i為父節點,其他的都是指向父節點的子節點int res = 0;for(int i = 0;i<len;i++){if(father[i]==i){res++;}}return res;}
};

image-20240509155516366

3、684. 冗余連接

在這里插入圖片描述

  • 在一棵樹中,邊的數量比節點的數量少 1。如果一棵樹有 n 個節點,則這棵樹有 n?1 條邊。這道題中的圖在樹的基礎上多了一條附加的邊,因此邊的數量也是 n。
  • 樹是一個連通且無環的無向圖,在樹中多了一條附加的邊之后就會出現環,因此附加的邊即為導致環出現的邊。
  • 可以通過并查集尋找附加的邊。初始時,每個節點都屬于不同的連通分量。遍歷每一條邊,判斷這條邊連接的兩個頂點是否屬于相同的連通分量。
  • 并查集解決問題:**只有出現環時,才會出現兩個根相同。**如果一棵樹有 n 個節點,則這棵樹有 n?1 條邊。那么這兩個節點根一定不同。

樹可以看成是一個連通且 無環無向 圖。

給定往一棵 n 個節點 (節點值 1~n) 的樹中添加一條邊后的圖。添加的邊的兩個頂點包含在 1n
中間,且這條附加的邊不屬于樹中已存在的邊。圖的信息記錄于長度為 n 的二維數組 edgesedges[i] = [ai, bi] 表示圖中在 aibi 之間存在一條邊。

請找出一條可以刪去的邊,刪除后可使得剩余部分是一個有著 n 個節點的樹。如果有多個答案,則返回數組 edges 中最后出現的那個。

示例 1:

img

輸入: edges = [[1,2], [1,3], [2,3]] 輸出: [2,3]

示例 2:

img

輸入: edges = [[1,2], [2,3], [3,4], [1,4], [1,5]] 輸出: [1,4]

提示:

  • n == edges.length
  • 3 <= n <= 1000
  • edges[i].length == 2
  • 1 <= ai < bi <= edges.length
  • ai != bi
  • edges 中無重復元素
  • 給定的圖是連通的
/*思路:題目中有個環:環比樹路徑多,找到重復的路徑一般的樹,不會出現,同一個根,只有環才可能出現兩個節點的根一樣
*/class Solution {
public:int n = 1001;vector<int> father{vector<int>(n)};void init() {for (int i = 0; i < n; i++) {father[i] = i;}}int find(int a) {if (a == father[a])return a;elsereturn father[a] = find(father[a]);}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;father[a] = b;}vector<int> findRedundantConnection(vector<vector<int>>& edges) {init();vector<int> res;for (auto& a : edges) {if (find(a[0]) == find(a[1])) {res = a;break;}join(a[0], a[1]);}return res;}
};

image-20240509181740502

4、 1061. 按字典序排列最小的等效字符串

給出長度相同的兩個字符串s1s2 ,還有一個字符串 baseStr

其中 s1[i]s2[i] 是一組等價字符。

  • 舉個例子,如果 s1 = "abc"s2 = "cde",那么就有 'a' == 'c', 'b' == 'd', 'c' == 'e'

等價字符遵循任何等價關系的一般規則:

  • 自反性'a' == 'a'
  • 對稱性'a' == 'b' 則必定有 'b' == 'a'
  • 傳遞性'a' == 'b''b' == 'c' 就表明 'a' == 'c'

例如, s1 = "abc"s2 = "cde" 的等價信息和之前的例子一樣,那么 baseStr = "eed" , "acd""aab",這三個字符串都是等價的,而 "aab"baseStr 的按字典序最小的等價字符串

利用 s1s2 的等價信息,找出并返回 baseStr 的按字典序排列最小的等價字符串。

示例 1:

輸入:s1 = "parker", s2 = "morris", baseStr = "parser"
輸出:"makkek"
解釋:根據 A 和 B 中的等價信息,我們可以將這些字符分為 [m,p], [a,o], [k,r,s], [e,i] 共 4 組。每組中的字符都是等價的,并按字典序排列。所以答案是 "makkek"。

示例 2:

輸入:s1 = "hello", s2 = "world", baseStr = "hold"
輸出:"hdld"
解釋:根據 A 和 B 中的等價信息,我們可以將這些字符分為 [h,w], [d,e,o], [l,r] 共 3 組。所以只有 S 中的第二個字符 'o' 變成 'd',最后答案為 "hdld"。

示例 3:

輸入:s1 = "leetcode", s2 = "programs", baseStr = "sourcecode"
輸出:"aauaaaaada"
解釋:我們可以把 A 和 B 中的等價字符分為 [a,o,e,r,s,c], [l,p], [g,t] 和 [d,m] 共 4 組,因此 S 中除了 'u' 和 'd' 之外的所有字母都轉化成了 'a',最后答案為 "aauaaaaada"。

提示:

  • 1 <= s1.length, s2.length, baseStr <= 1000
  • s1.length == s2.length
  • 字符串s1, s2, and baseStr 僅由從 'a''z' 的小寫英文字母組成。
/*思路:使用并查集將根節點都變成最小的,再遍歷一下全換成根就行有個坑點:if (find(s1[i]-'a') > find(s2[i]-'a'))這里需要每次找到根,再去判斷。
*/class Solution {
public:int n = 50;vector<int> father = vector<int>(n);void init() {for (int i = 0; i < father.size(); i++) {father[i] = i;}}int find(int a) {if (father[a] == a)return a;elsereturn father[a] = find(father[a]);}bool same(int a, int b) {a = find(a);b = find(b);return a == b;}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;elsefather[a] = b;}string smallestEquivalentString(string s1, string s2, string baseStr) {init();for (int i = 0; i < s1.size(); i++) {if (find(s1[i]-'a') > find(s2[i]-'a'))join(s1[i] - 'a', s2[i] - 'a');elsejoin(s2[i] - 'a', s1[i] - 'a');}for (auto& a : baseStr) {a = find(a-'a')+'a';}return baseStr;}
};

5、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:int n = 30;vector<int> father = vector<int>(n);void init() {for (int i = 0; i < n; i++) {father[i] = i;}}int find(int a) {if (a == father[a])return a;return father[a] = find(father[a]);}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;father[a] = b;}bool equationsPossible(vector<string>& equations) {init();for (auto& a : equations) {if (a[1] == '=')join(a[0] - 'a', a[3] - 'a');}for (auto& a : equations) {if (a[1] == '!') {if (find(a[0] - 'a') == find(a[3] - 'a')) {return false;}}}return true;}
};

6、947. 移除最多的同行或同列石頭

  • 解決連通性問題:記模板:x->y+max,如果聯通則最后結果都是最右邊的y+max

  • 把二維坐標平面上的石頭想象成圖的頂點,如果兩個石頭橫坐標相同、或者縱坐標相同,在它們之間形成一條邊。

    image-20240510011440239

    根據可以移除石頭的規則:如果一塊石頭的 同行或者同列 上有其他石頭存在,那么就可以移除這塊石頭。可以發現:一定可以把一個連通圖里的所有頂點根據這個規則刪到只剩下一個頂點。

n 塊石頭放置在二維平面中的一些整數坐標點上。每個坐標點上最多只能有一塊石頭。

如果一塊石頭的 同行或者同列 上有其他石頭存在,那么就可以移除這塊石頭。

給你一個長度為 n 的數組 stones ,其中 stones[i] = [xi, yi] 表示第 i 塊石頭的位置,返回 可以移除的石子 的最大數量。

示例 1:

1 1 0
1 0 1
0 1 1-》0->100  0->100->101 0
1->101  0           1->101->102
0       2->101->102 102->102102  102  0
102  0    102
0    102  1020 1 
1 0 0    0->1
1->0 00   0->101
1->100 0輸入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
輸出:5
解釋:一種移除 5 塊石頭的方法如下所示:
1. 移除石頭 [2,2] ,因為它和 [2,1] 同行。
2. 移除石頭 [2,1] ,因為它和 [0,1] 同列。
3. 移除石頭 [1,2] ,因為它和 [1,0] 同行。
4. 移除石頭 [1,0] ,因為它和 [0,0] 同列。
5. 移除石頭 [0,1] ,因為它和 [0,0] 同行。
石頭 [0,0] 不能移除,因為它沒有與另一塊石頭同行/列。

示例 2:

1 0 1
0 1 0
1 0 1
輸入:stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
輸出:3
解釋:一種移除 3 塊石頭的方法如下所示:
1. 移除石頭 [2,2] ,因為它和 [2,0] 同行。
2. 移除石頭 [2,0] ,因為它和 [0,0] 同列。
3. 移除石頭 [0,2] ,因為它和 [0,0] 同行。
石頭 [0,0] 和 [1,1] 不能移除,因為它們沒有與另一塊石頭同行/列。

示例 3:

輸入:stones = [[0,0]]
輸出:0
解釋:[0,0] 是平面上唯一一塊石頭,所以不可以移除它。

提示:

  • 1 <= stones.length <= 1000
  • 0 <= xi, yi <= 104
  • 不會有兩塊石頭放在同一個坐標點上
/*思路難以想象:只能記模板:把坐標x->y+10000上就能實現連通性分析問題:只要在坐標上是聯通的就可以得到同一個結果:同一個根:為什么?可以模擬出來,但是想不通注意:Y需要加上最大值:為了解決0  1 1  0的問題最后的結果都是:y的值最右邊y的值
*/class Solution {
public:int n = 51000;vector<int> father = vector<int>(n);void init() {for (int i = 0; i < father.size(); i++) {father[i] = i;}}int find(int a) {if (father[a] == a)return a;elsereturn father[a] = find(father[a]);}bool same(int a, int b) {a = find(a);b = find(b);return a == b;}void join(int a, int b) {a = find(a);b = find(b);if (a == b)return;elsefather[a] = b;}int removeStones(vector<vector<int>>& stones) {init();for (auto a : stones) {join(a[0], a[1] + 20005);}unordered_map<int, int> mp;for (auto a : stones) {mp[find(a[0])] = 1;}return stones.size() - mp.size();}
};

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

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

相關文章

精品推薦-湖倉一體電商數據分析平臺實踐教程合集(視頻教程+設計文檔+完整項目代碼)

精品推薦&#xff0c;湖倉一體電商數據分析平臺實踐教程合集&#xff0c;包含視頻教程、設計文檔及完整項目代碼等資料&#xff0c;供大家學習。 1、項目背景介紹及項目架構 2、項目使用技術版本及組件搭建 3、項目數據種類與采集 4、實時業務統計指標分析一——ODS分層設計與…

Git 基本操作(一)

目錄 git add git commit git log git status git diff git 版本回退 git reset git add git add 指令為添加工作區中的文件到暫存區中。 git add file_name; //將工作區名稱為file_name的文件添加進暫存區 git add .; //將工作區中的所有文件添加進暫存區 git comm…

docker打包鏡像時提示permission denied

sudo usermod -aG docker $USER //讓當前用戶加入docker用戶組 sudo systemctl restart docker //重新啟動docker服務 newgrp docker //更新組權限 來源&#xff1a;docker命令出現permission denied的解決方法_permission denied while trying to connect…

Deepseek常用高效提問模板!

DeepSeek高效提問秘籍大放送&#xff01; 掌握這些實用提問模板&#xff0c;能讓你與DeepSeek的對話更加精準、高效&#xff01; 1. 精準闡述需求 提問時務必清晰明確地表達問題或任務。例如&#xff1a; 欠佳的提問&#xff1a;“隨便說點內容。”優化后的提問&#xff1a…

地震資料偏移成像中,多次波(多次反射波)處理

在地震資料偏移成像中&#xff0c;多次波&#xff08;多次反射波&#xff09;會降低成像質量&#xff0c;導致虛假同相軸和構造假象。處理多次波需要結合波場分離和壓制技術&#xff0c;以下是主要方法和開源算法參考&#xff1a; 1. 多次波處理的核心方法 (1) 基于波場分離的…

quickbi finebi 測評(案例講解)

quickbi & finebi 測評 國產BI中入門門檻比較低的有兩個&#xff0c;分別是quickbi和finebi。根據我的經驗通過這篇文章做一個關于這兩款BI的測評文章。 quickbi分為個人版、高級版、專業版、私有化部署四種。這篇文章以quickbi高級版為例&#xff0c;對quickbi進行分享。…

【進階】--函數棧幀的創建和銷毀詳解

目錄 一.函數棧幀的概念 二.理解函數棧幀能讓我們解決什么問題 三.相關寄存器和匯編指令知識點補充 四.函數棧幀的創建和銷毀 4.1.調用堆棧 4.2.函數棧幀的創建 4.3 函數棧幀的銷毀 一.函數棧幀的概念 --在C語言中&#xff0c;函數棧幀是指在函數調用過程中&#xff0c;…

基于大模型預測的輸尿管癌診療全流程研究報告

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與創新點 二、大模型預測輸尿管癌的原理與方法 2.1 大模型技術概述 2.2 用于輸尿管癌預測的大模型選擇 2.3 數據收集與處理 2.4 模型訓練與優化 三、術前風險預測與手術方案制定 3.1 術前風險預測指標 3.2 大模型預測…

【Machine Learning Q and AI 讀書筆記】- 03 小樣本學習

Machine Learning Q and AI 中文譯名 大模型技術30講&#xff0c;主要總結了大模型相關的技術要點&#xff0c;結合學術和工程化&#xff0c;對LLM從業者來說&#xff0c;是一份非常好的學習實踐技術地圖. 本文是Machine Learning Q and AI 讀書筆記的第3篇&#xff0c;對應原…

PETR和位置編碼

PETR和位置編碼 petr檢測網絡中有2種類型的位置編碼。 正弦編碼和petr論文提出的3D Position Embedding。transformer模塊輸入除了qkv&#xff0c;還有query_pos和key_pos。這里重點記錄下query_pos和key_pos的生成 query pos的生成 先定義reference_points, shape為(n_query…

Ubuntu搭建 Nginx以及Keepalived 實現 主備

目錄 前言1. 基本知識2. Keepalived3. 腳本配置4. Nginx前言 ?? 找工作,來萬碼優才:?? #小程序://萬碼優才/r6rqmzDaXpYkJZF 爬蟲神器,無代碼爬取,就來:bright.cn Java基本知識: java框架 零基礎從入門到精通的學習路線 附開源項目面經等(超全)【Java項目】實戰CRU…

文章記單詞 | 第56篇(六級)

一&#xff0c;單詞釋義 interview /??nt?vju?/&#xff1a; 名詞&#xff1a;面試&#xff1b;采訪&#xff1b;面談動詞&#xff1a;對… 進行面試&#xff1b;采訪&#xff1b;接見 radioactive /?re?di???kt?v/&#xff1a;形容詞&#xff1a;放射性的&#xff…

MATLAB函數調用全解析:從入門到精通

在MATLAB編程中&#xff0c;函數是代碼復用的核心單元。本文將全面解析MATLAB中各類函數的調用方法&#xff0c;包括內置函數、自定義函數、匿名函數等&#xff0c;幫助提升代碼效率&#xff01; 一、MATLAB函數概述 MATLAB函數分為以下類型&#xff1a; 內置函數&#xff1a…

哈希表筆記(二)redis

Redis哈希表實現分析 這份代碼是Redis核心數據結構之一的字典(dict)實現&#xff0c;本質上是一個哈希表的實現。Redis的字典結構被廣泛用于各種內部數據結構&#xff0c;包括Redis數據庫本身和哈希鍵類型。 核心特點 雙表設計&#xff1a;每個字典包含兩個哈希表&#xff0…

PDF嵌入隱藏的文字

所需依賴 <dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>9.0.0</version><type>pom</type> </dependency>源碼 /*** PDF工具*/ public class PdfUtils {/*** 在 PD…

RAG工程-基于LangChain 實現 Advanced RAG(預檢索-查詢優化)(下)

Multi-Query 多路召回 多路召回流程圖 多路召回策略利用大語言模型&#xff08;LLM&#xff09;對原始查詢進行拓展&#xff0c;生成多個與原始查詢相關的問題&#xff0c;再將原始查詢和生成的所有相關問題一同發送給檢索系統進行檢索。它適用于用戶查詢比較寬泛、模糊或者需要…

【業務領域】PCIE協議理解

PCIE協議理解 提示&#xff1a;這里可以添加系列文章的所有文章的目錄&#xff0c;目錄需要自己手動添加 PCIE學習理解。 文章目錄 PCIE協議理解[TOC](文章目錄) 前言零、PCIE掌握點&#xff1f;一、PCIE是什么&#xff1f;二、PCIE協議總結物理層切速 鏈路層事務層6.2 TLP的路…

Jupyter notebook快捷鍵

文章目錄 Jupyter notebook鍵盤模式快捷鍵&#xff08;常用的已加粗&#xff09; Jupyter notebook鍵盤模式 命令模式&#xff1a;鍵盤輸入運行程序命令&#xff1b;這時單元格框線為藍色 編輯模式&#xff1a;允許你往單元格中鍵入代碼或文本&#xff1b;這時單元格框線是綠色…

Unity圖片導入設置

&#x1f3c6; 個人愚見&#xff0c;沒事寫寫筆記 &#x1f3c6;《博客內容》&#xff1a;Unity3D開發內容 &#x1f3c6;&#x1f389;歡迎 &#x1f44d;點贊?評論?收藏 &#x1f50e;Unity支持的圖片格式 ??BMP:是Windows操作系統的標準圖像文件格式&#xff0c;特點是…

Spark-小練試刀

任務1&#xff1a;HDFS上有三份文件&#xff0c;分別為student.txt&#xff08;學生信息表&#xff09;result_bigdata.txt&#xff08;大數據基礎成績表&#xff09;&#xff0c; result_math.txt&#xff08;數學成績表&#xff09;。 加載student.txt為名稱為student的RDD…