<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Union Find on 跟著 Desolve 學程式</title><link>https://desolve.pages.dev/tags/union-find/</link><description>Recent content in Union Find on 跟著 Desolve 學程式</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><lastBuildDate>Tue, 06 Jun 2023 00:00:00 +0800</lastBuildDate><atom:link href="https://desolve.pages.dev/tags/union-find/index.xml" rel="self" type="application/rss+xml"/><item><title>Learn Algorithms from LeetCode-120 (0547. Number of Provinces)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/</link><pubDate>Tue, 06 Jun 2023 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post Learn Algorithms from LeetCode-120 (0547. Number of Provinces)" /&gt;&lt;h2 id="categories-graphunion-find"&gt;Categories: Graph/Union Find
&lt;/h2&gt;&lt;h2 id="level-medium"&gt;Level: Medium**
&lt;/h2&gt;&lt;p&gt;Introduction: (Basic + Advanced + Interview Edition) &lt;br&gt;
Learning Algorithms from LeetCode + Interview Success Guide &lt;br&gt;
(Regular price: 3591 NTD, Discounted price until 2023/06/30 23:59)&lt;br&gt;
&lt;a class="link" href="https://hiskio.com/bundles/eCP23B397?s=tc" target="_blank" rel="noopener"
&gt;https://hiskio.com/bundles/eCP23B397?s=tc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Regular price: 3990 NTD, Valid for a long term) &lt;br&gt;
&lt;a class="link" href="https://bit.ly/lc2022all" target="_blank" rel="noopener"
&gt;https://bit.ly/lc2022all&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please help me click on the “SHOW EMBED” below and give it 5 likes~ If you like it, you can also give me a round of applause~ &lt;br&gt;
(Liking doesn’t cost anything, thank you for supporting my writing~)&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;There are &lt;code&gt;n&lt;/code&gt; cities. Some of them are connected, while some are not. If city &lt;code&gt;a&lt;/code&gt; is connected directly with city &lt;code&gt;b&lt;/code&gt;, and city &lt;code&gt;b&lt;/code&gt; is connected directly with city &lt;code&gt;c&lt;/code&gt;, then city &lt;code&gt;a&lt;/code&gt; is connected indirectly with city &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;province&lt;/strong&gt; is a group of directly or indirectly connected cities and no other cities outside of the group.&lt;/p&gt;
&lt;p&gt;You are given an &lt;code&gt;n x n&lt;/code&gt; matrix &lt;code&gt;isConnected&lt;/code&gt; where &lt;code&gt;isConnected[i][j] = 1&lt;/code&gt; if the &lt;code&gt;ith&lt;/code&gt; city and the &lt;code&gt;jth&lt;/code&gt; city are directly connected, and &lt;code&gt;isConnected[i][j] = 0&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;p&gt;Return &lt;em&gt;the total number of&lt;/em&gt; *&lt;strong&gt;provinces&lt;/strong&gt; *.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_gzPQzUPCV6vo5zpO.jpg"
width="222"
height="142"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_gzPQzUPCV6vo5zpO_hu_57f2b94360956ce8.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_gzPQzUPCV6vo5zpO_hu_9e1c69c1f2e289c0.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="375px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_vYmD9XAZJEU4Isbo.jpg"
width="222"
height="142"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_vYmD9XAZJEU4Isbo_hu_af71b661ff852cd7.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/0_vYmD9XAZJEU4Isbo_hu_48eac003d0a48d17.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="375px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= n &amp;lt;= 200&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n == isConnected.length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n == isConnected[i].length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][j]&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][i] == 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][j] == isConnected[j][i]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Analysis/Approach:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are n cities, some of which are directly connected to each other, while others are not. If city a is directly connected to city b, and city b is directly connected to city c, then city a is indirectly connected to city c. (That’s a lot of unnecessary words LOL)&lt;/p&gt;
&lt;p&gt;A province is a group of cities that are directly or indirectly connected, and there are no other cities in this group. (In other words, if you can walk from x to y, they are considered part of the same province).&lt;/p&gt;
&lt;p&gt;Given an n x n matrix isConnected, where isConnected[i][j] = 1 means the ith city is directly connected to the jth city, and isConnected[i][j] = 0 means they are not directly connected, return the total number of provinces.&lt;/p&gt;
&lt;p&gt;We have discussed many concepts related to graphs in &lt;a class="link" href="https://desolve.medium.com/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-115-graph-1-union-find-1-3616ad4a6496" target="_blank" rel="noopener"
&gt;&lt;strong&gt;Article 115&lt;/strong&gt; &lt;/a&gt; and the previous article. Today, let’s take a closer look at the usage of Union Find.&lt;/p&gt;
&lt;p&gt;Since the variable name “isConnected” is too long, we will use “edges” to refer to it for convenience.&lt;/p&gt;
&lt;p&gt;First, we need to find the number of provinces, which is another typical scenario where Union Find can be used. However, as we mentioned before, if we only trace back along the edges to find the root, the find operation for a single point can potentially take &lt;strong&gt;O(n)&lt;/strong&gt; time. Therefore, we need to simplify the process by performing ** path compression** during the ** union** operation.&lt;/p&gt;
&lt;p&gt;In the union operation, instead of arbitrary assignment as before, we can now choose to check which root has a higher rank and merge the group with the lower rank into the group with the higher rank. The root of the group with the lower rank should be set as the root of the group with the higher rank. This way, during the union process, since we always merge the smaller group into the larger one, it will be less likely to create long chains of connections. This technique is called &lt;strong&gt;path compression&lt;/strong&gt; .&lt;/p&gt;
&lt;p&gt;Therefore, our implementation of the find operation and union operation will look like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;find(root, i)&lt;/strong&gt; :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initialize r as root[i]&lt;/li&gt;
&lt;li&gt;If r and root[r] are not equal (indicating that we haven’t reached the node that is the root), enter the loop:&lt;/li&gt;
&lt;li&gt;Set root[r] as root[root[r]]&lt;/li&gt;
&lt;li&gt;Set r as root[r] (move up one level and continue the evaluation)&lt;/li&gt;
&lt;li&gt;After the loop (steps 2–4) ends, set root[i] as r, indicating that the topmost leader of node i is r.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;union(root, rank, x, y):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Apply the find operation to x and y separately to obtain their respective roots &lt;strong&gt;rx and ry&lt;/strong&gt; .&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;rx and ry are the same&lt;/strong&gt; , it means they are already in the same group, so &lt;strong&gt;return false&lt;/strong&gt; .&lt;/li&gt;
&lt;li&gt;If they are different, compare the ranks rank[rx] and rank[ry]:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;strong&gt;rank[rx] ≥ rank[ry]&lt;/strong&gt; , increase rank[rx] by rank[ry] and &lt;strong&gt;set root[ry] as rx&lt;/strong&gt; .&lt;/li&gt;
&lt;li&gt;Otherwise, if &lt;strong&gt;rank[rx] &amp;lt; rank[ry]&lt;/strong&gt; , increase rank[ry] by rank[rx] and &lt;strong&gt;set root[rx] as ry&lt;/strong&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After initializing root and rank (from &lt;strong&gt;1 to n-1&lt;/strong&gt; and ** 1**), we can use a nested loop to call the union operation for the pairs of cities that are connected by edges. Finally, we iterate through each node and perform the find operation to determine the ** unique roots** and store them in a HashSet. The answer can be obtained by checking the size of the HashSet.&lt;/p&gt;
&lt;p&gt;Here is an implementation in Java:&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;We can use &lt;strong&gt;Arrays.fill()&lt;/strong&gt; to set values in Java. Since we don’t specifically need the true/false return value for the union operation, we can change its return type to void and modify the necessary parts accordingly. Finally, we can use a HashSet to record the answers, iterate through i, call find(), and add the results. The final answer can be obtained by checking the size of the HashSet.&lt;/p&gt;
&lt;p&gt;Notice that you could start j from i+1 rather than 0.&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/26aa057a36ea78c2d4511cba41333eeb.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;In Python, the implementation is similar except for the use of sub-functions.&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/40a58853d50c6c18acded10bee487bac.js"&gt;&lt;/script&gt;
&lt;p&gt;&lt;strong&gt;Potential Interview Questions:&lt;/strong&gt;&lt;br&gt;
“What are the time and space complexities?”&lt;br&gt;
(O(n²)/O(n), as even with path compression, traversing all edges still takes O(n²) time, and the space complexity only needs to consider the space for recording roots and ranks.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Similar and Extended Topics:&lt;/strong&gt; 0684. Redundant Connection (Medium)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special thanks to suggestions/corrections from viewers:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;(Welcome to provide feedback to help with corrections~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Learn Algorithms from LeetCode — See you next time!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Want to see more problems? &lt;br&gt;
Feel free to check out &lt;a class="link" href="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-0/" &gt;&lt;strong&gt;Article 0&lt;/strong&gt; &lt;/a&gt; for the topic you want!&lt;/p&gt;
&lt;p&gt;Also, follow our Facebook page for notifications on new articles:&lt;br&gt;
&lt;a class="link" href="https://www.facebook.com/learnwithdesolve" target="_blank" rel="noopener"
&gt;&lt;strong&gt;Learn with Desolve&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法-120 (0547. Number of Provinces)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/</link><pubDate>Tue, 06 Jun 2023 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法-120 (0547. Number of Provinces)" /&gt;&lt;h2 id="categories-graphunion-find"&gt;Categories: Graph/Union Find
&lt;/h2&gt;&lt;h2 id="level-medium"&gt;Level: Medium
&lt;/h2&gt;&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;(基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**&lt;/p&gt;
&lt;p&gt;(3591元 特價中: 2023/06/30 23:59後截止) &lt;br&gt;
&lt;a class="link" href="https://hiskio.com/bundles/eCP23B397?s=tc" target="_blank" rel="noopener"
&gt;https://hiskio.com/bundles/eCP23B397?s=tc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(3990元 長期有效) &lt;a class="link" href="https://bit.ly/lc2022all" target="_blank" rel="noopener"
&gt;https://bit.ly/lc2022all&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;容筆者工商一下，&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」&lt;/strong&gt; 這次選了40道難度加深的LeetCode題目，&lt;br&gt;
同樣也會細部解說對應的技巧及須要掌握的演算法！&lt;br&gt;
同時這次購買進階篇的話，&lt;br&gt;
額外還加贈**「從Leetcode學演算法｜面試篇」** ！&lt;br&gt;
當中包含了&lt;strong&gt;面試準備須知分享&lt;/strong&gt; ，&lt;strong&gt;及訪談國內外不同經驗的工程師&lt;/strong&gt; ，&lt;br&gt;
讓你不論是&lt;strong&gt;想走前端/後端/一般軟工&lt;/strong&gt; 或者是&lt;strong&gt;想找國外的工作&lt;/strong&gt; ，&lt;br&gt;
是&lt;strong&gt;初學想轉職&lt;/strong&gt; 還是&lt;strong&gt;正在工作&lt;/strong&gt; ，都能夠從中得到收穫呦！&lt;br&gt;
有興趣的朋友可以使用下面的優惠～&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」&lt;/strong&gt; ：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/lc2022adv" target="_blank" rel="noopener"
&gt;https://bit.ly/lc2022adv&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;There are &lt;code&gt;n&lt;/code&gt; cities. Some of them are connected, while some are not. If city &lt;code&gt;a&lt;/code&gt; is connected directly with city &lt;code&gt;b&lt;/code&gt;, and city &lt;code&gt;b&lt;/code&gt; is connected directly with city &lt;code&gt;c&lt;/code&gt;, then city &lt;code&gt;a&lt;/code&gt; is connected indirectly with city &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;province&lt;/strong&gt; is a group of directly or indirectly connected cities and no other cities outside of the group.&lt;/p&gt;
&lt;p&gt;You are given an &lt;code&gt;n x n&lt;/code&gt; matrix &lt;code&gt;isConnected&lt;/code&gt; where &lt;code&gt;isConnected[i][j] = 1&lt;/code&gt; if the &lt;code&gt;ith&lt;/code&gt; city and the &lt;code&gt;jth&lt;/code&gt; city are directly connected, and &lt;code&gt;isConnected[i][j] = 0&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;p&gt;Return &lt;em&gt;the total number of&lt;/em&gt; *&lt;strong&gt;provinces&lt;/strong&gt; *.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_gzPQzUPCV6vo5zpO.jpg"
width="222"
height="142"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_gzPQzUPCV6vo5zpO_hu_57f2b94360956ce8.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_gzPQzUPCV6vo5zpO_hu_9e1c69c1f2e289c0.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="375px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_vYmD9XAZJEU4Isbo.jpg"
width="222"
height="142"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_vYmD9XAZJEU4Isbo_hu_af71b661ff852cd7.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/0_vYmD9XAZJEU4Isbo_hu_48eac003d0a48d17.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="375px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= n &amp;lt;= 200&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n == isConnected.length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n == isConnected[i].length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][j]&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][i] == 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConnected[i][j] == isConnected[j][i]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;有n個城市，其中一些城市彼此相連，而另一些則沒有。&lt;br&gt;
如果城市a與城市b直接相連，並且城市b與城市c直接相連，&lt;br&gt;
那麼城市a與城市c之間間接相連。(OS: 好廢話XD)&lt;/p&gt;
&lt;p&gt;一個省(province)是一組直接或間接相連的城市，&lt;br&gt;
且該群組中沒有其他的城市。&lt;br&gt;
(也就是直要可以從x走到y，它們就視為相同省)&lt;/p&gt;
&lt;p&gt;給定一個n x n的矩陣isConnected，&lt;br&gt;
其中isConnected[i][j] = 1表示第i個城市和第j個城市直接相連，isConnected[i][j] = 0則表示它們不直接相連，回傳省的總數量。&lt;/p&gt;
&lt;p&gt;我們已經在&lt;a class="link" href="https://desolve.medium.com/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-115-graph-1-union-find-1-3616ad4a6496" target="_blank" rel="noopener"
&gt;&lt;strong&gt;第115篇&lt;/strong&gt; &lt;/a&gt;以及上一篇中提到了很多Graph的概念，&lt;br&gt;
今天再來仔細一點探討Union Find的用法。&lt;/p&gt;
&lt;p&gt;由於isConnected太長了，我們底下還是直接使用edges來稱呼比較簡便。&lt;br&gt;
首先看到了要找provinces的組數，&lt;br&gt;
顯然又是一個很典型能使用Union Find的場合；&lt;br&gt;
但先前我們提到過，如果只是一路沿著edge往回trace老大的話，&lt;br&gt;
對於單一點的find有可能達到O(n)，&lt;br&gt;
因此我們需要做一些簡化：在&lt;strong&gt;union&lt;/strong&gt; 的合併時，&lt;br&gt;
就盡可能地&lt;strong&gt;先行收斂&lt;/strong&gt; 。那麼我們應該怎麼做呢？&lt;/p&gt;
&lt;p&gt;我們這邊定義一個串列叫做rank，&lt;br&gt;
用以表達每個節點往上對到的root所含有的節點總數。&lt;br&gt;
那麼在合併的時候，有別於先前的任意指定，&lt;br&gt;
我們這次可以選擇先檢查誰的rank大，&lt;br&gt;
接著&lt;strong&gt;人多欺負人少&lt;/strong&gt; &amp;hellip;&amp;hellip;不對，是&lt;strong&gt;rank大的合併掉rank小&lt;/strong&gt; 的群組；&lt;br&gt;
rank小的群組的root要設定為rank大的群組的root。&lt;br&gt;
這麼一來，在合併的過程中，由於一直是大的合併小的，&lt;br&gt;
相對而言會較不容易將union的連接拉太多層，&lt;br&gt;
這個手法我們稱之為&lt;strong&gt;路徑壓縮(path compression)&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;因此，我們的find的寫法和union的寫法會像這樣：&lt;br&gt;
&lt;strong&gt;find(root, i):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先取到r = root[i]&lt;/li&gt;
&lt;li&gt;如果r和root[r]不相等(代表還沒走到自己是root(老大)的節點)進行迴圈:&lt;/li&gt;
&lt;li&gt;將root[root[r]]的值塞給root[r]&lt;/li&gt;
&lt;li&gt;令r = root[r] (來到上面一層，繼續準備判斷)&lt;/li&gt;
&lt;li&gt;在2~4的迴圈結束後，直接令root[i] = r，&lt;br&gt;
標明節點i的最上面的老大是r。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;union(root, rank, x, y):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;對x, y分別使用find，取得各自的root &lt;strong&gt;rx, ry&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果&lt;strong&gt;rx和ry相同&lt;/strong&gt; ，代表已經是同一組了，&lt;strong&gt;直接回傳false&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果不同，則看rank[rx]和rank[ry]的關係，&lt;br&gt;
&lt;strong&gt;rank[rx] ≥ rank[ry]&lt;/strong&gt; 的話，就將&lt;strong&gt;rank[rx]遞增rank[ry]&lt;/strong&gt; ，&lt;br&gt;
並且令&lt;strong&gt;root[ry] = rx&lt;/strong&gt; ；&lt;br&gt;
反之，若&lt;strong&gt;rank[rx] &amp;lt; rank[ry]&lt;/strong&gt; ，則將&lt;strong&gt;rank[ry]遞增rank[rx]&lt;/strong&gt; ，&lt;br&gt;
並且令&lt;strong&gt;root[rx] = ry&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那麼，剩下來我們只需要做完對root和rank的初始化(&lt;strong&gt;1~n-1&lt;/strong&gt; 跟&lt;strong&gt;1&lt;/strong&gt; )&lt;br&gt;
剩下就是&lt;strong&gt;雙層迴圈&lt;/strong&gt; 對有&lt;strong&gt;edge&lt;/strong&gt; 的兩點呼叫&lt;strong&gt;union&lt;/strong&gt; ，&lt;br&gt;
最後對於每個節點確認它們&lt;strong&gt;不重複的root有哪些&lt;/strong&gt; 即可。&lt;/p&gt;
&lt;p&gt;依此，寫成程式碼如下：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分一樣可以用&lt;strong&gt;Arrays.fill()&lt;/strong&gt; 來設定定值，&lt;br&gt;
同時因為我們union其實沒特別用到true/false的需求，&lt;br&gt;
可以設定為void，直接將對應該改的東西改一改，&lt;br&gt;
並直接return即可。&lt;/p&gt;
&lt;p&gt;同時，在記錄答案時，我們可以使用HashSet，&lt;br&gt;
在最後對i做遍歷並逐個進行find()，並加到當中，&lt;br&gt;
最後檢查res.size()即可得到我們要的答案。&lt;/p&gt;
&lt;p&gt;另外可以留意的是，雙重迴圈的union(i, j)因為沒有方向性的關係，&lt;br&gt;
第二層的j可以&lt;strong&gt;從i+1開始&lt;/strong&gt; 就好，不需要從0開始。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/26aa057a36ea78c2d4511cba41333eeb.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分除了改成用子函式以外，&lt;br&gt;
其餘則大同小異。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/40a58853d50c6c18acded10bee487bac.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
( O(n²)/O(n)，因為即便有經過path的壓縮，遍歷所有edge仍然要O(n²)，&lt;br&gt;
空間的部分則是只需要考慮記錄root和rank的空間)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;ol start="684"&gt;
&lt;li&gt;Redundant Connection (Medium)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;想看看其他題目嗎？&lt;br&gt;
歡迎從&lt;a class="link" href="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-0/" &gt;&lt;strong&gt;第零篇&lt;/strong&gt; &lt;/a&gt;找你想要的！&lt;/p&gt;
&lt;p&gt;同時追蹤粉專以獲得更多新文章的通知：&lt;br&gt;
&lt;a class="link" href="https://www.facebook.com/learnwithdesolve" target="_blank" rel="noopener"
&gt;&lt;strong&gt;跟著Desolve學程式&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;strong&gt;「從Leetcode學演算法｜基礎篇」&lt;/strong&gt; 已經回原價囉，&lt;br&gt;
先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，&lt;br&gt;
雖然&lt;strong&gt;整捆一起買總體比較划算&lt;/strong&gt; (差290而已就有整組了阿XD)，&lt;br&gt;
如果你還是想先試試基礎課的話，&lt;br&gt;
&lt;strong&gt;300元折抵的連結&lt;/strong&gt; 在這邊：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/lc2022base" target="_blank" rel="noopener"
&gt;https://bit.ly/lc2022base&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 115 Graph(1) / Union Find (1)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/</link><pubDate>Sun, 04 Jul 2021 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 115 Graph(1) / Union Find (1)" /&gt;&lt;p&gt;&lt;strong&gt;0684. Redundant Connection (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;從 LeetCode 學演算法 + 面試成功指南**&lt;a class="link" href="https://bit.ly/zeroclg?fbclid=IwAR0cGOc6L5R4j26i6BqncG0m1tPPPx5-Z1M0vAOzJpnwUrByX3q-gWE1Sfw" target="_blank" rel="noopener"
&gt;http://bit.ly/zeroclg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;容筆者工商一下，&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」&lt;/strong&gt; 這次選了40道難度加深的LeetCode題目，&lt;br&gt;
同樣也會細部解說對應的技巧及須要掌握的演算法！&lt;br&gt;
同時這次購買進階篇的話，&lt;br&gt;
額外還加贈**「從Leetcode學演算法｜面試篇」** ！&lt;br&gt;
當中包含了&lt;strong&gt;面試準備須知分享&lt;/strong&gt; ，&lt;strong&gt;及訪談國內外不同經驗的工程師&lt;/strong&gt; ，&lt;br&gt;
讓你不論是&lt;strong&gt;想走前端/後端/一般軟工&lt;/strong&gt; 或者是&lt;strong&gt;想找國外的工作&lt;/strong&gt; ，&lt;br&gt;
是&lt;strong&gt;初學想轉職&lt;/strong&gt; 還是&lt;strong&gt;正在工作&lt;/strong&gt; ，都能夠從中得到收穫呦！&lt;br&gt;
有興趣的朋友可以使用下面的優惠～&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」&lt;/strong&gt; ：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/leetcodeadv" target="_blank" rel="noopener"
&gt;https://bit.ly/leetcodeadv&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;In this problem, a tree is an &lt;strong&gt;undirected graph&lt;/strong&gt; that is connected and has no cycles.&lt;/p&gt;
&lt;p&gt;You are given a graph that started as a tree with &lt;code&gt;n&lt;/code&gt; nodes labeled from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;, with one additional edge added. The added edge has two &lt;strong&gt;different&lt;/strong&gt; vertices chosen from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;, and was not an edge that already existed. The graph is represented as an array &lt;code&gt;edges&lt;/code&gt; of length &lt;code&gt;n&lt;/code&gt; where &lt;code&gt;edges[i] = [ai, bi]&lt;/code&gt; indicates that there is an edge between nodes &lt;code&gt;ai&lt;/code&gt; and &lt;code&gt;bi&lt;/code&gt; in the graph.&lt;/p&gt;
&lt;p&gt;Return &lt;em&gt;an edge that can be removed so that the resulting graph is a tree of&lt;/em&gt; &lt;code&gt;n&lt;/code&gt; &lt;em&gt;nodes&lt;/em&gt;. If there are multiple answers, return the answer that occurs last in the input.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_m69nQSg0Xz1tu5mf.jpg"
width="222"
height="222"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_m69nQSg0Xz1tu5mf_hu_3326d65e86806957.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_m69nQSg0Xz1tu5mf_hu_9bed4f62bccceac9.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="100"
data-flex-basis="240px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: edges = [[1,2],[1,3],[2,3]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: [2,3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_saAjSjHo_CMHr584.jpg"
width="382"
height="222"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_saAjSjHo_CMHr584_hu_17679c459b72d567.jpg 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/0_saAjSjHo_CMHr584_hu_4ad50aa88815e03a.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="172"
data-flex-basis="412px"
&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: [1,4]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;n == edges.length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3 &amp;lt;= n &amp;lt;= 1000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edges[i].length == 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= ai &amp;lt; bi &amp;lt;= edges.length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ai != bi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;There are no repeated edges.&lt;/li&gt;
&lt;li&gt;The given graph is connected.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;在這個問題中，一棵樹是一個無向圖(undirected graph)，且當中沒有環(cycle)。給定一個圖，當中有n個node，標記為從1到n，其中有多一個邊(edge)；多出來的邊是由1到n選出兩個不同的節點(vertices, vertex的複數)所構成的，且並非已經存在的邊。這個圖是由一個長度為n的陣列edges來表示的，其每個元素edges[i]=[ai, bi]表示在圖中，ai和bi兩個節點中間有一個邊連結。&lt;/p&gt;
&lt;p&gt;請回傳一個可以在移除後令這個圖可以形成一棵含有n個節點的樹的邊，如果有多個答案的話，請回傳讓其發生在最後的輸入。&lt;/p&gt;
&lt;p&gt;好的，光翻譯題目就是一個很麻煩的事情，這也是為什麼從之前到現在始終不太想作圖(graph)相關的文章：因為實在太麻煩了，且不好解釋XD&lt;/p&gt;
&lt;p&gt;那我們今天就來挑戰看看吧！希望在看完本篇文章以後，大家還醒著(笑)XD&lt;/p&gt;
&lt;p&gt;在解這題之前，我們應該要先對圖作一點基本介紹：&lt;br&gt;
圖(graph)是一種描述資料與資料之間的連結(不是人與人之間的)的結構，&lt;br&gt;
當中最主要會分為兩個主要的元素：vertex(節點)及edge(邊/線段)。&lt;br&gt;
節點可能擁有自己的一些屬性或值，這個可以依照定義而改變，而節點和節點之間，則是透過邊來連接，因此在同一張圖內，如果有超過一個節點，那它們至少要有能夠相連的邊連結彼此(不然就不會是同一張圖了！)。&lt;/p&gt;
&lt;p&gt;接下來另一個很重要的點是，圖可以分為&lt;strong&gt;有向圖(directed graph)&lt;/strong&gt; 和&lt;strong&gt;無向圖(undirected graph)&lt;/strong&gt; ，什麼意思呢？&lt;/p&gt;
&lt;p&gt;舉例來說，筆者對台北還不夠熟悉的時候，騎著機車在台北附近總是容易繞一大圈才走到自己的目的地，而且回程的時候還容易繞錯路，其中一個原因就是&lt;strong&gt;單行道&lt;/strong&gt; 。單行道表示了今天從A走到B可能可以走XX路，但從B到A可能要走OO路接RR路才行，因為XX路是單向的；換句話說，當從A到B和從B到A無法等價看待的時候，我們會稱這樣的圖為有向圖，因為其關連性不能夠直接反過來也成立。這種圖在繪製上的體現就是節點到節點之間會&lt;strong&gt;有箭頭以表示方向&lt;/strong&gt; ，對於本題來說，由於給定是無方向的，所以讀者會看到圖形上的連接僅有線條，沒有箭頭。&lt;/p&gt;
&lt;p&gt;接著是&lt;strong&gt;環(cycle)&lt;/strong&gt; ，如果一個圖可以從某個節點出發，經過&lt;strong&gt;不重複&lt;/strong&gt; 的節點(起點除外)，最終又能回到起始的節點，我們稱這個圖具有一個循環。&lt;/p&gt;
&lt;p&gt;圖的表示方式一般有兩種：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Adjacency Matrix(相鄰矩陣)，也就是如果有N個節點，就開一個NxN的矩陣Mat，當中如果A點跟B點有edge的話，Mat[A][B]=1，否則為0；可以想見，如果某個圖是無向圖的話，這個矩陣應該會沿對角線相對稱(因為Mat[A][B]會和Mat[B][A]等價)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adjacency List(相鄰串列)，也就是對每個節點，都用一個串列來列出跟這個節點有相連的邊的所有節點。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一般而言，如果總體的edge數量較多的話會使用相鄰矩陣，比較少的話則會使用相鄰串列。&lt;/p&gt;
&lt;p&gt;其它跟圖有關的基礎其實還很多，我們容後有機會再慢慢講。&lt;/p&gt;
&lt;p&gt;回到我們的題目，其實它是一個相對簡單的圖，&lt;br&gt;
因為要連接n個節點總體只需要n-1個邊，而這個圖有n個邊，&lt;br&gt;
要讓這個圖不成環，只能將其中一個會構成環的邊給去除掉。&lt;/p&gt;
&lt;p&gt;那麼，我們怎麼知道哪邊會有環成立呢？&lt;br&gt;
這邊我們可以使用union find的概念來處理。&lt;br&gt;
union find其實是在探究&lt;strong&gt;併查集(&lt;/strong&gt; Disjoint-set data structure**)** 的問題。&lt;br&gt;
用最白話的方式，就是「我們有沒有同一國」的概念。&lt;br&gt;
什麼意思呢？&lt;/p&gt;
&lt;p&gt;假設一個班級有幾個小團體，這些小團體跟幫派一樣很講17且不能重覆加入，我們現在想知道究竟哪些同學屬於哪個小團體，要怎麼找呢？&lt;br&gt;
其實很簡單，就是把每個同學叫過來問：「你的老大是誰？」&lt;/p&gt;
&lt;p&gt;舉例來說，如果有一個班級有兩個小團體，它們之間的層級分部是這樣的：&lt;/p&gt;
&lt;p&gt;A&lt;br&gt;
| &lt;br&gt;
B C&lt;br&gt;
| | &lt;br&gt;
DE- F&lt;/p&gt;
&lt;p&gt;G&lt;br&gt;
|&lt;br&gt;
H&lt;br&gt;
|&lt;br&gt;
I&lt;/p&gt;
&lt;p&gt;D會告訴你他的老大是B；&lt;br&gt;
E會告訴你他的老大是C；&lt;br&gt;
然後B、C會告訴你他們的老大是A；&lt;br&gt;
最後問到A他會說：「我就是老大！」&lt;br&gt;
於是我們就會發現B、C、D、E這四位其實都是隸屬於A的，&lt;br&gt;
也就是他們都是同一團體的。而G、H、I則屬於另一個團體。&lt;br&gt;
因此，我們可以對某個節點找到它最上層的節點，&lt;br&gt;
用這個節點來定義它所屬的團體，同時在過程中依照新增的邊來合併彼此的老大，這個過程叫作&lt;strong&gt;find&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;那麼，我們換個角度來思考：&lt;br&gt;
依照上面的概念，每個節點之間的邊，其實就可以代表它們是同一國的，&lt;br&gt;
那麼，如果在看到這個邊之前，它們就已經有相同的老大了呢？&lt;br&gt;
比如上面的圖而言，&lt;strong&gt;對於E和F來說，由於有A-C-E跟A-C-F，&lt;br&gt;
因此E跟F都知道自己的老大是A&lt;/strong&gt;。&lt;br&gt;
接著我們看到E-F的這條邊連結起來，就意味著這邊&lt;strong&gt;構成了一個環&lt;/strong&gt; ！&lt;br&gt;
因為前面E已經可以連到A，F也可以連到A表示EAF之間可以連接起來，&lt;br&gt;
因此E-F的連接就給這之間構成了一個環。&lt;/p&gt;
&lt;p&gt;因此，我們可以利用這點，來找出構成環的邊，就是我們要的答案了！&lt;br&gt;
因為節點和邊的總數量我們知道是n，所有節點也只有1~n，&lt;br&gt;
所以我們可以使用一個陣列或串列來簡單表示某個節點的老大是哪個節點。&lt;br&gt;
如果它自己就是最大的老大的話，那麼我們就用-1來代表它沒有更上層了。&lt;/p&gt;
&lt;p&gt;因此，我們的解題步驟應該像這樣：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;產生一個root的陣列/串列，其長度為&lt;strong&gt;n+1&lt;/strong&gt; (比較方便對應1~n)，&lt;br&gt;
其初始值均為**-1** 。&lt;/li&gt;
&lt;li&gt;對於edges中的每個邊edge，使用&lt;strong&gt;find&lt;/strong&gt; 函式找到它們的老大x跟y，&lt;br&gt;
檢查x和y是否相同；&lt;strong&gt;若相同，表示這個邊構成了一個環&lt;/strong&gt; ，回傳&lt;strong&gt;edge&lt;/strong&gt; 即可；&lt;br&gt;
若不同，則須統一老大，將&lt;strong&gt;root[x]設定為y&lt;/strong&gt; (將x這系列的上層往y這邊合併)。&lt;/li&gt;
&lt;li&gt;如果檢查完均檢查不到，則在外層回傳空的陣列/串列表示沒找到(但題目表示應該都會存在答案，所以理論上不會走到這邊)。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在&lt;strong&gt;find函式&lt;/strong&gt; 的定義中，輸入應該是root這個陣列跟要被確認的節點i：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用迴圈，當&lt;strong&gt;root[i]不是-1時，令i = root[i]&lt;/strong&gt; ，往上找尋更上層的老大。&lt;/li&gt;
&lt;li&gt;直到迴圈結束，這時候的i應該是最上層了，就&lt;strong&gt;回傳i&lt;/strong&gt; 即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;依此，寫成程式碼如下：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部份可以使用Arrays.fill來給定一整組的陣列初始值。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/596d829af98746c03991688cfae63b09.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分則直接用*號來初始化即可，同時使用子函式，&lt;br&gt;
略去self相關的麻煩寫法。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/718f00bd8c163db8cabb118bb6ef35ee.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(如果找尋root的時間沒有到最糟糕狀況的話為O(N)/O(N)，但我們在這個版本的只實作了find，最差狀況下find會一條線接上去，導致find的複雜度達到O(N)，這時候總體時間複雜度就會是O(N^2)。)&lt;/p&gt;
&lt;p&gt;「如果要實作化簡的部份的話？」&lt;br&gt;
(化簡的概念在於將中間尋找的部分也一併處理，也就是告訴沿路上的所有節點它們最大的老大是誰，要怎麼作才能讓整個路徑更短，可以參見&lt;a class="link" href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure" target="_blank" rel="noopener"
&gt;https://en.wikipedia.org/wiki/Disjoint-set_data_structure&lt;/a&gt;，或者參考LeetCode的Solution也有提供，原則上是看兩個小團之間的節點數量來進行誰併到誰的決定。)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;想看看其他題目嗎？&lt;br&gt;
歡迎從&lt;a class="link" href="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-0/" &gt;&lt;strong&gt;第零篇&lt;/strong&gt; &lt;/a&gt;找你想要的！&lt;/p&gt;
&lt;p&gt;同時追蹤粉專以獲得更多新文章的通知：&lt;br&gt;
&lt;a class="link" href="https://www.facebook.com/learnwithdesolve" target="_blank" rel="noopener"
&gt;&lt;strong&gt;跟著Desolve學程式&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;strong&gt;「從Leetcode學演算法｜基礎篇」&lt;/strong&gt; 已經回原價囉，&lt;br&gt;
先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，&lt;br&gt;
雖然&lt;strong&gt;整捆一起買總體比較划算&lt;/strong&gt; (差290而已就有整組了阿XD)，&lt;br&gt;
如果你還是想先試試基礎課的話，&lt;br&gt;
&lt;strong&gt;300元折抵的連結&lt;/strong&gt; 在這邊：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/1desolve" target="_blank" rel="noopener"
&gt;https://bit.ly/1desolve&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>