<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>union find Archives - Huahua&#039;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/union-find/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog/tag/union-find/</link>
	<description></description>
	<lastBuildDate>Sat, 14 Jan 2023 20:26:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.8</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>union find Archives - Huahua&#039;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog/tag/union-find/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 1061. Lexicographically Smallest Equivalent String</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1061-lexicographically-smallest-equivalent-string/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1061-lexicographically-smallest-equivalent-string/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 14 Jan 2023 20:24:29 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9916</guid>

					<description><![CDATA[<p>You are given two strings of the same length&#160;s1&#160;and&#160;s2&#160;and a string&#160;baseStr. We say&#160;s1[i]&#160;and&#160;s2[i]&#160;are equivalent characters. For example, if&#160;s1 = "abc"&#160;and&#160;s2 = "cde", then we have&#160;'a'&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1061-lexicographically-smallest-equivalent-string/">花花酱 LeetCode 1061. Lexicographically Smallest Equivalent String</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given two strings of the same length&nbsp;<code>s1</code>&nbsp;and&nbsp;<code>s2</code>&nbsp;and a string&nbsp;<code>baseStr</code>.</p>



<p>We say&nbsp;<code>s1[i]</code>&nbsp;and&nbsp;<code>s2[i]</code>&nbsp;are equivalent characters.</p>



<ul><li>For example, if&nbsp;<code>s1 = "abc"</code>&nbsp;and&nbsp;<code>s2 = "cde"</code>, then we have&nbsp;<code>'a' == 'c'</code>,&nbsp;<code>'b' == 'd'</code>, and&nbsp;<code>'c' == 'e'</code>.</li></ul>



<p>Equivalent characters follow the usual rules of any equivalence relation:</p>



<ul><li><strong>Reflexivity:</strong>&nbsp;<code>'a' == 'a'</code>.</li><li><strong>Symmetry:</strong>&nbsp;<code>'a' == 'b'</code>&nbsp;implies&nbsp;<code>'b' == 'a'</code>.</li><li><strong>Transitivity:</strong>&nbsp;<code>'a' == 'b'</code>&nbsp;and&nbsp;<code>'b' == 'c'</code>&nbsp;implies&nbsp;<code>'a' == 'c'</code>.</li></ul>



<p>For example, given the equivalency information from&nbsp;<code>s1 = "abc"</code>&nbsp;and&nbsp;<code>s2 = "cde"</code>,&nbsp;<code>"acd"</code>&nbsp;and&nbsp;<code>"aab"</code>&nbsp;are equivalent strings of&nbsp;<code>baseStr = "eed"</code>, and&nbsp;<code>"aab"</code>&nbsp;is the lexicographically smallest equivalent string of&nbsp;<code>baseStr</code>.</p>



<p>Return&nbsp;<em>the lexicographically smallest equivalent string of&nbsp;</em><code>baseStr</code><em>&nbsp;by using the equivalency information from&nbsp;</em><code>s1</code><em>&nbsp;and&nbsp;</em><code>s2</code>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s1 = "parker", s2 = "morris", baseStr = "parser"
<strong>Output:</strong> "makkek"
<strong>Explanation:</strong> Based on the equivalency information in s1 and s2, we can group their characters as [m,p], [a,o], [k,r,s], [e,i].
The characters in each group are equivalent and sorted in lexicographical order.
So the answer is "makkek".
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s1 = "hello", s2 = "world", baseStr = "hold"
<strong>Output:</strong> "hdld"
<strong>Explanation: </strong>Based on the equivalency information in s1 and s2, we can group their characters as [h,w], [d,e,o], [l,r].
So only the second letter 'o' in baseStr is changed to 'd', the answer is "hdld".
</pre>



<p><strong>Example 3:</strong></p>



<pre class="crayon-plain-tag">&lt;strong&gt;Input:&lt;/strong&gt; s1 = &quot;leetcode&quot;, s2 = &quot;programs&quot;, baseStr = &quot;sourcecode&quot;
&lt;strong&gt;Output:&lt;/strong&gt; &quot;aauaaaaada&quot;
&lt;strong&gt;Explanation:&lt;/strong&gt; We group the equivalent characters in s1 and s2 as [a,o,e,r,s,c], [l,p], [g,t] and [d,m], thus all letters in baseStr except 'u' and 'd' are transformed to 'a', the answer is &quot;aauaaaaada&quot;.</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= s1.length, s2.length, baseStr &lt;= 1000</code></li><li><code>s1.length == s2.length</code></li><li><code>s1</code>,&nbsp;<code>s2</code>, and&nbsp;<code>baseStr</code>&nbsp;consist of lowercase English letters.</li></ul>



<h2><strong>Solution: Union Find</strong></h2>



<figure class="wp-block-image size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2023/01/1061-s1.png"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2023/01/1061-s1.png" alt="" class="wp-image-9918" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2023/01/1061-s1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2023/01/1061-s1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2023/01/1061-s1-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></a></figure>



<p>Time complexity: O(n + m)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  string smallestEquivalentString(string s1, string s2, string baseStr) {
    vector&lt;int&gt; p(26);
    iota(begin(p), end(p), 0);
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return p[x] == x ? x : p[x] = find(p[x]);
    };
    for (int i = 0; i &lt; s1.length(); ++i) {
      int r1 = find(s1[i] - 'a');
      int r2 = find(s2[i] - 'a');
      if (r2 &lt; r1) swap(r1, r2);
      p[r2] = r1;
    }
    
    string ans(baseStr);
    for (int i = 0; i &lt; baseStr.length(); ++i) {
      ans[i] = find(baseStr[i] - 'a') + 'a';
    }
    return ans;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1061-lexicographically-smallest-equivalent-string/">花花酱 LeetCode 1061. Lexicographically Smallest Equivalent String</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1061-lexicographically-smallest-equivalent-string/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2316. Count Unreachable Pairs of Nodes in an Undirected Graph</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-2316-count-unreachable-pairs-of-nodes-in-an-undirected-graph/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-2316-count-unreachable-pairs-of-nodes-in-an-undirected-graph/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 25 Jun 2022 23:07:42 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9761</guid>

					<description><![CDATA[<p>You are given an integer n. There is an undirected graph with n nodes, numbered from 0 to n - 1. You are given a 2D integer array edges where edges[i] = [ai, bi] denotes that there&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2316-count-unreachable-pairs-of-nodes-in-an-undirected-graph/">花花酱 LeetCode 2316. Count Unreachable Pairs of Nodes in an Undirected Graph</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 2316. Count Unreachable Pairs of Nodes in an Undirected Graph - 刷题找工作 EP397" width="500" height="281" src="https://www.youtube.com/embed/vH9CLfE82Rk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>You are given an integer <code>n</code>. There is an <strong>undirected</strong> graph with <code>n</code> nodes, numbered from <code>0</code> to <code>n - 1</code>. You are given a 2D integer array <code>edges</code> where <code>edges[i] = [a<sub>i</sub>, b<sub>i</sub>]</code> denotes that there exists an <strong>undirected</strong> edge connecting nodes <code>a<sub>i</sub></code> and <code>b<sub>i</sub></code>.</p>



<p>Return&nbsp;<em>the&nbsp;<strong>number of pairs</strong>&nbsp;of different nodes that are&nbsp;<strong>unreachable</strong>&nbsp;from each other</em>.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2022/05/05/tc-3.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 3, edges = [[0,1],[0,2],[1,2]]
<strong>Output:</strong> 0
<strong>Explanation:</strong> There are no pairs of nodes that are unreachable from each other. Therefore, we return 0.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2022/05/05/tc-2.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
<strong>Output:</strong> 14
<strong>Explanation:</strong> There are 14 pairs of nodes that are unreachable from each other:
[[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]].
Therefore, we return 14.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>0 &lt;= edges.length &lt;= 2 * 10<sup>5</sup></code></li><li><code>edges[i].length == 2</code></li><li><code>0 &lt;= a<sub>i</sub>, b<sub>i</sub>&nbsp;&lt; n</code></li><li><code>a<sub>i</sub>&nbsp;!= b<sub>i</sub></code></li><li>There are no repeated edges.</li></ul>



<h2><strong>Solution 1: DFS</strong></h2>



<p>Use DFS to find all CCs</p>



<p>Time complexity: O(V+E)<br>Space complexity: O(V+E)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
// Author: Huahua, 791ms, 136 MB
class Solution {
public:
  long long countPairs(int n, vector&lt;vector&lt;int&gt;&gt;&amp; edges) {
    vector&lt;vector&lt;int&gt;&gt; g(n);
    for (const auto&amp; e : edges) {
      g[e[0]].push_back(e[1]);
      g[e[1]].push_back(e[0]);
    }
    vector&lt;int&gt; seen(n);
    long long cur = 0;
    
    function&lt;void(int)&gt; dfs = [&amp;](int u) {
      ++cur;
      for (int v : g[u])
        if (seen[v]++ == 0) dfs(v);      
    };
    long long ans = 0;    
    for (int i = 0; i &lt; n; ++i) {
      if (seen[i]++) continue;
      cur = 0;
      dfs(i);
      ans += (n - cur) * cur;
    }
    return ans / 2;
  }
};</pre>
</div></div>



<h2><strong>Solution 2: Union Find</strong></h2>



<p>Time complexity: O(V+E)<br>Space complexity: O(V)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  long long countPairs(int n, vector&lt;vector&lt;int&gt;&gt;&amp; edges) {
    vector&lt;int&gt; parents(n);
    vector&lt;int&gt; counts(n, 1);
    std::iota(begin(parents), end(parents), 0);
    
    function&lt;int(int)&gt; find = [&amp;](int x) {
      if (parents[x] == x) return x;
      return parents[x] = find(parents[x]);
    };
    
    for (const auto&amp; e : edges) {
      int ru = find(e[0]);
      int rv = find(e[1]);
      if (ru != rv) {
        parents[rv] = ru;
        counts[ru] += counts[rv];        
      }
    }
    long long ans = 0;    
    for (int i = 0; i &lt; n; ++i)      
      ans += n - counts[find(i)];
    return ans / 2;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2316-count-unreachable-pairs-of-nodes-in-an-undirected-graph/">花花酱 LeetCode 2316. Count Unreachable Pairs of Nodes in an Undirected Graph</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-2316-count-unreachable-pairs-of-nodes-in-an-undirected-graph/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2157. Groups of Strings</title>
		<link>https://zxi.mytechroad.com/blog/searching/leetcode-2157-groups-of-strings/</link>
					<comments>https://zxi.mytechroad.com/blog/searching/leetcode-2157-groups-of-strings/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 07 Feb 2022 01:03:45 +0000</pubDate>
				<category><![CDATA[Search]]></category>
		<category><![CDATA[connected components]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9492</guid>

					<description><![CDATA[<p>You are given a&#160;0-indexed&#160;array of strings&#160;words. Each string consists of&#160;lowercase English letters&#160;only. No letter occurs more than once in any string of&#160;words. Two strings&#160;s1&#160;and&#160;s2&#160;are said&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/searching/leetcode-2157-groups-of-strings/">花花酱 LeetCode 2157. Groups of Strings</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;array of strings&nbsp;<code>words</code>. Each string consists of&nbsp;<strong>lowercase English letters</strong>&nbsp;only. No letter occurs more than once in any string of&nbsp;<code>words</code>.</p>



<p>Two strings&nbsp;<code>s1</code>&nbsp;and&nbsp;<code>s2</code>&nbsp;are said to be&nbsp;<strong>connected</strong>&nbsp;if the set of letters of&nbsp;<code>s2</code>&nbsp;can be obtained from the set of letters of&nbsp;<code>s1</code>&nbsp;by any&nbsp;<strong>one</strong>&nbsp;of the following operations:</p>



<ul><li>Adding exactly one letter to the set of the letters of&nbsp;<code>s1</code>.</li><li>Deleting exactly one letter from the set of the letters of&nbsp;<code>s1</code>.</li><li>Replacing exactly one letter from the set of the letters of&nbsp;<code>s1</code>&nbsp;with any letter,&nbsp;<strong>including</strong>&nbsp;itself.</li></ul>



<p>The array&nbsp;<code>words</code>&nbsp;can be divided into one or more non-intersecting&nbsp;<strong>groups</strong>. A string belongs to a group if any&nbsp;<strong>one</strong>&nbsp;of the following is true:</p>



<ul><li>It is connected to&nbsp;<strong>at least one</strong>&nbsp;other string of the group.</li><li>It is the&nbsp;<strong>only</strong>&nbsp;string present in the group.</li></ul>



<p>Note that the strings in&nbsp;<code>words</code>&nbsp;should be grouped in such a manner that a string belonging to a group cannot be connected to a string present in any other group. It can be proved that such an arrangement is always unique.</p>



<p>Return&nbsp;<em>an array</em>&nbsp;<code>ans</code>&nbsp;<em>of size</em>&nbsp;<code>2</code>&nbsp;<em>where:</em></p>



<ul><li><code>ans[0]</code>&nbsp;<em>is the&nbsp;<strong>total number</strong>&nbsp;of groups</em>&nbsp;<code>words</code>&nbsp;<em>can be divided into, and</em></li><li><code>ans[1]</code>&nbsp;<em>is the&nbsp;<strong>size of the largest</strong>&nbsp;group</em>.</li></ul>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> words = ["a","b","ab","cde"]
<strong>Output:</strong> [2,3]
<strong>Explanation:</strong>
- words[0] can be used to obtain words[1] (by replacing 'a' with 'b'), and words[2] (by adding 'b'). So words[0] is connected to words[1] and words[2].
- words[1] can be used to obtain words[0] (by replacing 'b' with 'a'), and words[2] (by adding 'a'). So words[1] is connected to words[0] and words[2].
- words[2] can be used to obtain words[0] (by deleting 'b'), and words[1] (by deleting 'a'). So words[2] is connected to words[0] and words[1].
- words[3] is not connected to any string in words.
Thus, words can be divided into 2 groups ["a","b","ab"] and ["cde"]. The size of the largest group is 3.  
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> words = ["a","ab","abc"]
<strong>Output:</strong> [1,3]
<strong>Explanation:</strong>
- words[0] is connected to words[1].
- words[1] is connected to words[0] and words[2].
- words[2] is connected to words[1].
Since all strings are connected to each other, they should be grouped together.
Thus, the size of the largest group is 3.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= words.length &lt;= 2 * 10<sup>4</sup></code></li><li><code>1 &lt;= words[i].length &lt;= 26</code></li><li><code>words[i]</code>&nbsp;consists of lowercase English letters only.</li><li>No letter occurs more than once in&nbsp;<code>words[i]</code>.</li></ul>



<h2><strong>Solution: Bitmask + DFS</strong></h2>



<p>Use a bitmask to represent a string. Use dfs to find connected components.</p>



<p>Time complexity: O(n*26<sup>2</sup>)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;int&gt; groupStrings(vector&lt;string&gt;&amp; words) {
    unordered_map&lt;int, int&gt; m;
    for (const string&amp; w : words)
      ++m[accumulate(begin(w), end(w), 0, [](int k, char c){ return k | (1 &lt;&lt; (c - 'a')); })];
    function&lt;int(int)&gt; dfs = [&amp;](int mask) {
      auto it = m.find(mask);
      if (it == end(m)) return 0;
      int ans = it-&gt;second;      
      m.erase(it);
      for (int i = 0; i &lt; 26; ++i) {        
        ans += dfs(mask ^ (1 &lt;&lt; i));
        for (int j = i + 1; j &lt; 26; ++j)
          if ((mask &gt;&gt; i &amp; 1) != (mask &gt;&gt; j &amp; 1))
            ans += dfs(mask ^ (1 &lt;&lt; i) ^ (1 &lt;&lt; j));
      }
      return ans;
    };
    int size = 0;
    int groups = 0;
    while (!m.empty()) {
      size = max(size, dfs(begin(m)-&gt;first));
      ++groups;
    }
    return {groups, size};
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/searching/leetcode-2157-groups-of-strings/">花花酱 LeetCode 2157. Groups of Strings</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/searching/leetcode-2157-groups-of-strings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1998. GCD Sort of an Array</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1998-gcd-sort-of-an-array/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1998-gcd-sort-of-an-array/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 01 Jan 2022 06:49:23 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[gcd]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[prime]]></category>
		<category><![CDATA[sqrt]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9383</guid>

					<description><![CDATA[<p>You are given an integer array&#160;nums, and you can perform the following operation&#160;any&#160;number of times on&#160;nums: Swap the positions of two elements&#160;nums[i]&#160;and&#160;nums[j]&#160;if&#160;gcd(nums[i], nums[j]) &#62; 1&#160;where&#160;gcd(nums[i],&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1998-gcd-sort-of-an-array/">花花酱 LeetCode 1998. GCD Sort of an Array</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given an integer array&nbsp;<code>nums</code>, and you can perform the following operation&nbsp;<strong>any</strong>&nbsp;number of times on&nbsp;<code>nums</code>:</p>



<ul><li>Swap the positions of two elements&nbsp;<code>nums[i]</code>&nbsp;and&nbsp;<code>nums[j]</code>&nbsp;if&nbsp;<code>gcd(nums[i], nums[j]) &gt; 1</code>&nbsp;where&nbsp;<code>gcd(nums[i], nums[j])</code>&nbsp;is the&nbsp;<strong>greatest common divisor</strong>&nbsp;of&nbsp;<code>nums[i]</code>&nbsp;and&nbsp;<code>nums[j]</code>.</li></ul>



<p>Return&nbsp;<code>true</code>&nbsp;<em>if it is possible to sort&nbsp;</em><code>nums</code><em>&nbsp;in&nbsp;<strong>non-decreasing</strong>&nbsp;order using the above swap method, or&nbsp;</em><code>false</code><em>&nbsp;otherwise.</em></p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [7,21,3]
<strong>Output:</strong> true
<strong>Explanation:</strong> We can sort [7,21,3] by performing the following operations:
- Swap 7 and 21 because gcd(7,21) = 7. nums = [<strong>21</strong>,<strong>7</strong>,3]
- Swap 21 and 3 because gcd(21,3) = 3. nums = [<strong>3</strong>,7,<strong>21</strong>]
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [5,2,6,2]
<strong>Output:</strong> false
<strong>Explanation:</strong> It is impossible to sort the array because 5 cannot be swapped with any other element.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [10,5,9,3,15]
<strong>Output:</strong> true
We can sort [10,5,9,3,15] by performing the following operations:
- Swap 10 and 15 because gcd(10,15) = 5. nums = [<strong>15</strong>,5,9,3,<strong>10</strong>]
- Swap 15 and 3 because gcd(15,3) = 3. nums = [<strong>3</strong>,5,9,<strong>15</strong>,10]
- Swap 10 and 15 because gcd(10,15) = 5. nums = [3,5,9,<strong>10</strong>,<strong>15</strong>]
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= nums.length &lt;= 3 * 10<sup>4</sup></code></li><li><code>2 &lt;= nums[i] &lt;= 10<sup>5</sup></code></li></ul>



<h2><strong>Solution: Union-Find</strong></h2>



<p>Let nums[j]&#8217;s target position be i. In order to put nums[j] to pos i by swapping. nums[i] and nums[j] must be in the same connected component. There is an edge between two numbers if they have gcd > 1.</p>



<p>We union two numbers if their have gcd > 1. However, it will be TLE if we do all pairs . Thus, for each number, we union it with its divisors instead.</p>



<p>Time complexity: O(n<sup>2</sup>) TLE -> O(sum(sqrt(nums[i]))) &lt;= O(n*sqrt(m))<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  bool gcdSort(vector&lt;int&gt;&amp; nums) {
    const int m = *max_element(begin(nums), end(nums));
    const int n = nums.size();
    
    vector&lt;int&gt; p(m + 1);
    iota(begin(p), end(p), 0);
  
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return p[x] == x ? x : (p[x] = find(p[x]));
    };
  
    for (int x : nums)
      for (int d = 2; d &lt;= sqrt(x); ++d)
        if (x % d == 0)
          p[find(x)] = p[find(x / d)] = find(d);

    vector&lt;int&gt; sorted(nums);
    sort(begin(sorted), end(sorted));
    
    for (int i = 0; i &lt; n; ++i)
      if (find(sorted[i]) != find(nums[i])) 
        return false;

    return true;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1998-gcd-sort-of-an-array/">花花酱 LeetCode 1998. GCD Sort of an Array</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1998-gcd-sort-of-an-array/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2092. Find All People With Secret</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-2092-find-all-people-with-secret/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-2092-find-all-people-with-secret/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 28 Nov 2021 17:44:35 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=8859</guid>

					<description><![CDATA[<p>You are given an integer&#160;n&#160;indicating there are&#160;n&#160;people numbered from&#160;0&#160;to&#160;n - 1. You are also given a&#160;0-indexed&#160;2D integer array&#160;meetings&#160;where&#160;meetings[i] = [xi, yi, timei]&#160;indicates that person&#160;xi&#160;and person&#160;yi&#160;have&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2092-find-all-people-with-secret/">花花酱 LeetCode 2092. Find All People With Secret</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given an integer&nbsp;<code>n</code>&nbsp;indicating there are&nbsp;<code>n</code>&nbsp;people numbered from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>n - 1</code>. You are also given a&nbsp;<strong>0-indexed</strong>&nbsp;2D integer array&nbsp;<code>meetings</code>&nbsp;where&nbsp;<code>meetings[i] = [x<sub>i</sub>, y<sub>i</sub>, time<sub>i</sub>]</code>&nbsp;indicates that person&nbsp;<code>x<sub>i</sub></code>&nbsp;and person&nbsp;<code>y<sub>i</sub></code>&nbsp;have a meeting at&nbsp;<code>time<sub>i</sub></code>. A person may attend&nbsp;<strong>multiple meetings</strong>&nbsp;at the same time. Finally, you are given an integer&nbsp;<code>firstPerson</code>.</p>



<p>Person&nbsp;<code>0</code>&nbsp;has a&nbsp;<strong>secret</strong>&nbsp;and initially shares the secret with a person&nbsp;<code>firstPerson</code>&nbsp;at time&nbsp;<code>0</code>. This secret is then shared every time a meeting takes place with a person that has the secret. More formally, for every meeting, if a person&nbsp;<code>x<sub>i</sub></code>&nbsp;has the secret at&nbsp;<code>time<sub>i</sub></code>, then they will share the secret with person&nbsp;<code>y<sub>i</sub></code>, and vice versa.</p>



<p>The secrets are shared&nbsp;<strong>instantaneously</strong>. That is, a person may receive the secret and share it with people in other meetings within the same time frame.</p>



<p>Return&nbsp;<em>a list of all the people that have the secret after all the meetings have taken place.&nbsp;</em>You may return the answer in&nbsp;<strong>any order</strong>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1
<strong>Output:</strong> [0,1,2,3,5]
<strong>Explanation:
</strong>At time 0, person 0 shares the secret with person 1.
At time 5, person 1 shares the secret with person 2.
At time 8, person 2 shares the secret with person 3.
At time 10, person 1 shares the secret with person 5.​​​​
Thus, people 0, 1, 2, 3, and 5 know the secret after all the meetings.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, meetings = [[3,1,3],[1,2,2],[0,3,3]], firstPerson = 3
<strong>Output:</strong> [0,1,3]
<strong>Explanation:</strong>
At time 0, person 0 shares the secret with person 3.
At time 2, neither person 1 nor person 2 know the secret.
At time 3, person 3 shares the secret with person 0 and person 1.
Thus, people 0, 1, and 3 know the secret after all the meetings.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, meetings = [[3,4,2],[1,2,1],[2,3,1]], firstPerson = 1
<strong>Output:</strong> [0,1,2,3,4]
<strong>Explanation:</strong>
At time 0, person 0 shares the secret with person 1.
At time 1, person 1 shares the secret with person 2, and person 2 shares the secret with person 3.
Note that person 2 can share the secret at the same time as receiving it.
At time 2, person 3 shares the secret with person 4.
Thus, people 0, 1, 2, 3, and 4 know the secret after all the meetings.
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, meetings = [[0,2,1],[1,3,1],[4,5,1]], firstPerson = 1
<strong>Output:</strong> [0,1,2,3]
<strong>Explanation:</strong>
At time 0, person 0 shares the secret with person 1.
At time 1, person 0 shares the secret with person 2, and person 1 shares the secret with person 3.
Thus, people 0, 1, 2, and 3 know the secret after all the meetings.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>2 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= meetings.length &lt;= 10<sup>5</sup></code></li><li><code>meetings[i].length == 3</code></li><li><code>0 &lt;= x<sub>i</sub>, y<sub>i&nbsp;</sub>&lt;= n - 1</code></li><li><code>x<sub>i</sub>&nbsp;!= y<sub>i</sub></code></li><li><code>1 &lt;= time<sub>i</sub>&nbsp;&lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= firstPerson &lt;= n - 1</code></li></ul>



<h2><strong>Solution: Union Find</strong></h2>



<p>Sorting meetings by time.</p>



<p>At each time stamp, union people who meet.<br>Key step: &#8220;<strong><span class="has-inline-color has-vivid-red-color">un-union</span></strong>&#8221; people if they <strong><span class="has-inline-color has-vivid-red-color">DO NOT</span></strong> connected to 0 / known the secret after each timestamp.</p>



<p>Time complexity: O(nlogn + m + n)<br>Space complexity: O(m + n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;int&gt; findAllPeople(int n, vector&lt;vector&lt;int&gt;&gt;&amp; meetings, int firstPerson) {        
    map&lt;int, vector&lt;pair&lt;int, int&gt;&gt;&gt; events;
    for (const auto&amp; m : meetings)
      events[m[2]].emplace_back(m[0], m[1]);
    vector&lt;int&gt; p(n);
    iota(begin(p), end(p), 0);
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return p[x] == x ? x : (p[x] = find(p[x]));
    };
    p[firstPerson] = 0;
    for (const auto&amp; [t, s] : events) {
      for (const auto [u, v] : s)
        p[find(u)] = find(v);
      for (const auto [u, v] : s) {
        if (find(u) != find(0)) p[u] = u;
        if (find(v) != find(0)) p[v] = v;
      }
    }    
    vector&lt;int&gt; ans;
    for (int i = 0; i &lt; n; ++i)
      if (find(i) == find(0)) ans.push_back(i);
    return ans;
  }
};</pre>
</div></div>



<h2><strong>Related Problems</strong></h2>



<ul><li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/">花花酱 LeetCode 1202. Smallest String With Swaps</a></li><li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/" data-type="post" data-id="6962">花花酱 LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree</a></li><li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/" data-type="post" data-id="8719">花花酱 LeetCode 2076. Process Restricted Friend Requests</a></li><li><a href="https://zxi.mytechroad.com/blog/uncategorized/leetcode-1722-minimize-hamming-distance-after-swap-operations/" data-type="post" data-id="7967">花花酱 LeetCode 1722. Minimize Hamming Distance After Swap Operations</a></li><li><a href="https://zxi.mytechroad.com/blog/data-structure/sp1-union-find-set/" data-type="post" data-id="1039">花花酱 LeetCode Disjoint set / Union Find Forest SP1</a></li></ul>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2092-find-all-people-with-secret/">花花酱 LeetCode 2092. Find All People With Secret</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-2092-find-all-people-with-secret/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2076. Process Restricted Friend Requests</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 15 Nov 2021 21:04:13 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=8719</guid>

					<description><![CDATA[<p>You are given an integer&#160;n&#160;indicating the number of people in a network. Each person is labeled from&#160;0&#160;to&#160;n - 1. You are also given a&#160;0-indexed&#160;2D integer&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/">花花酱 LeetCode 2076. Process Restricted Friend Requests</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given an integer&nbsp;<code>n</code>&nbsp;indicating the number of people in a network. Each person is labeled from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>n - 1</code>.</p>



<p>You are also given a&nbsp;<strong>0-indexed</strong>&nbsp;2D integer array&nbsp;<code>restrictions</code>, where&nbsp;<code>restrictions[i] = [x<sub>i</sub>, y<sub>i</sub>]</code>&nbsp;means that person&nbsp;<code>x<sub>i</sub></code>&nbsp;and person&nbsp;<code>y<sub>i</sub></code>&nbsp;<strong>cannot&nbsp;</strong>become&nbsp;<strong>friends</strong>,either&nbsp;<strong>directly</strong>&nbsp;or&nbsp;<strong>indirectly</strong>&nbsp;through other people.</p>



<p>Initially, no one is friends with each other. You are given a list of friend requests as a&nbsp;<strong>0-indexed</strong>&nbsp;2D integer array&nbsp;<code>requests</code>, where&nbsp;<code>requests[j] = [u<sub>j</sub>, v<sub>j</sub>]</code>&nbsp;is a friend request between person&nbsp;<code>u<sub>j</sub></code>&nbsp;and person&nbsp;<code>v<sub>j</sub></code>.</p>



<p>A friend request is&nbsp;<strong>successful&nbsp;</strong>if&nbsp;<code>u<sub>j</sub></code>&nbsp;and&nbsp;<code>v<sub>j</sub></code>&nbsp;can be&nbsp;<strong>friends</strong>. Each friend request is processed in the given order (i.e.,&nbsp;<code>requests[j]</code>&nbsp;occurs before&nbsp;<code>requests[j + 1]</code>), and upon a successful request,&nbsp;<code>u<sub>j</sub></code>&nbsp;and&nbsp;<code>v<sub>j</sub></code>&nbsp;<strong>become direct friends</strong>&nbsp;for all future friend requests.</p>



<p>Return&nbsp;<em>a&nbsp;<strong>boolean array</strong>&nbsp;</em><code>result</code>,<em>&nbsp;where each&nbsp;</em><code>result[j]</code><em>&nbsp;is&nbsp;</em><code>true</code><em>&nbsp;if the&nbsp;</em><code>j<sup>th</sup></code><em>&nbsp;friend request is&nbsp;<strong>successful</strong>&nbsp;or&nbsp;</em><code>false</code><em>&nbsp;if it is not</em>.</p>



<p><strong>Note:</strong>&nbsp;If&nbsp;<code>u<sub>j</sub></code>&nbsp;and&nbsp;<code>v<sub>j</sub></code>&nbsp;are already direct friends, the request is still&nbsp;<strong>successful</strong>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 3, restrictions = [[0,1]], requests = [[0,2],[2,1]]
<strong>Output:</strong> [true,false]
<strong>Explanation:
</strong>Request 0: Person 0 and person 2 can be friends, so they become direct friends. 
Request 1: Person 2 and person 1 cannot be friends since person 0 and person 1 would be indirect friends (1--2--0).
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 3, restrictions = [[0,1]], requests = [[1,2],[0,2]]
<strong>Output:</strong> [true,false]
<strong>Explanation:
</strong>Request 0: Person 1 and person 2 can be friends, so they become direct friends.
Request 1: Person 0 and person 2 cannot be friends since person 0 and person 1 would be indirect friends (0--2--1).
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, restrictions = [[0,1],[1,2],[2,3]], requests = [[0,4],[1,2],[3,1],[3,4]]
<strong>Output:</strong> [true,false,true,false]
<strong>Explanation:
</strong>Request 0: Person 0 and person 4 can be friends, so they become direct friends.
Request 1: Person 1 and person 2 cannot be friends since they are directly restricted.
Request 2: Person 3 and person 1 can be friends, so they become direct friends.
Request 3: Person 3 and person 4 cannot be friends since person 0 and person 1 would be indirect friends (0--4--3--1).
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>2 &lt;= n &lt;= 1000</code></li><li><code>0 &lt;= restrictions.length &lt;= 1000</code></li><li><code>restrictions[i].length == 2</code></li><li><code>0 &lt;= x<sub>i</sub>, y<sub>i</sub>&nbsp;&lt;= n - 1</code></li><li><code>x<sub>i</sub>&nbsp;!= y<sub>i</sub></code></li><li><code>1 &lt;= requests.length &lt;= 1000</code></li><li><code>requests[j].length == 2</code></li><li><code>0 &lt;= u<sub>j</sub>, v<sub>j</sub>&nbsp;&lt;= n - 1</code></li><li><code>u<sub>j</sub>&nbsp;!= v<sub>j</sub></code></li></ul>



<p><strong>Solution: Union Find / Brute Force</strong></p>



<p>For each request, check all restrictions.</p>



<p>Time complexity: O(req * res)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;bool&gt; friendRequests(int n, vector&lt;vector&lt;int&gt;&gt;&amp; restrictions, vector&lt;vector&lt;int&gt;&gt;&amp; requests) {
    vector&lt;int&gt; parents(n);
    iota(begin(parents), end(parents), 0);
    function&lt;int(int)&gt; find = [&amp;](int x) {
      if (parents[x] == x) return x;
      return parents[x] = find(parents[x]);
    };
    auto check = [&amp;](int u, int v) {
      for (const auto&amp; r : restrictions) {
        int pu = find(r[0]);
        int pv = find(r[1]);
        if ((pu == u &amp;&amp; pv == v) || (pu == v &amp;&amp; pv == u))
          return false;
      }
      return true;
    };
    vector&lt;bool&gt; ans;
    for (const auto&amp; r : requests) {      
      int pu = find(r[0]);
      int pv = find(r[1]);
      if (pu == pv || check(pu, pv)) {
        parents[pu] = pv;
        ans.push_back(true);
      } else {
        ans.push_back(false);
      }
    }
    return ans;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/">花花酱 LeetCode 2076. Process Restricted Friend Requests</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-2076-process-restricted-friend-requests/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1697. Checking Existence of Edge Length Limited Paths</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1697-checking-existence-of-edge-length-limited-paths/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1697-checking-existence-of-edge-length-limited-paths/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 20 Dec 2020 10:00:20 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[sorting]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7830</guid>

					<description><![CDATA[<p>An undirected graph of&#160;n&#160;nodes is defined by&#160;edgeList, where&#160;edgeList[i] = [ui, vi, disi]&#160;denotes an edge between nodes&#160;ui&#160;and&#160;vi&#160;with distance&#160;disi. Note that there may be&#160;multiple&#160;edges between two nodes.&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1697-checking-existence-of-edge-length-limited-paths/">花花酱 LeetCode 1697. Checking Existence of Edge Length Limited Paths</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>An undirected graph of&nbsp;<code>n</code>&nbsp;nodes is defined by&nbsp;<code>edgeList</code>, where&nbsp;<code>edgeList[i] = [u<sub>i</sub>, v<sub>i</sub>, dis<sub>i</sub>]</code>&nbsp;denotes an edge between nodes&nbsp;<code>u<sub>i</sub></code>&nbsp;and&nbsp;<code>v<sub>i</sub></code>&nbsp;with distance&nbsp;<code>dis<sub>i</sub></code>. Note that there may be&nbsp;<strong>multiple</strong>&nbsp;edges between two nodes.</p>



<p>Given an array&nbsp;<code>queries</code>, where&nbsp;<code>queries[j] = [p<sub>j</sub>, q<sub>j</sub>, limit<sub>j</sub>]</code>, your task is to determine for each&nbsp;<code>queries[j]</code>&nbsp;whether there is a path between&nbsp;<code>p<sub>j</sub></code>&nbsp;and&nbsp;<code>q<sub>j</sub></code>such that each edge on the path has a distance&nbsp;<strong>strictly less than</strong>&nbsp;<code>limit<sub>j</sub></code>&nbsp;.</p>



<p>Return&nbsp;<em>a&nbsp;<strong>boolean array</strong>&nbsp;</em><code>answer</code><em>, where&nbsp;</em><code>answer.length == queries.length</code>&nbsp;<em>and the&nbsp;</em><code>j<sup>th</sup></code>&nbsp;<em>value of&nbsp;</em><code>answer</code>&nbsp;<em>is&nbsp;</em><code>true</code><em>&nbsp;if there is a path for&nbsp;</em><code>queries[j]</code><em>&nbsp;is&nbsp;</em><code>true</code><em>, and&nbsp;</em><code>false</code><em>&nbsp;otherwise</em>.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/12/08/h.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 3, edgeList = [[0,1,2],[1,2,4],[2,0,8],[1,0,16]], queries = [[0,1,2],[0,2,5]]
<strong>Output:</strong> [false,true]
<strong>Explanation:</strong> The above figure shows the given graph. Note that there are two overlapping edges between 0 and 1 with distances 2 and 16.
For the first query, between 0 and 1 there is no path where each distance is less than 2, thus we return false for this query.
For the second query, there is a path (0 -&gt; 1 -&gt; 2) of two edges with distances less than 5, thus we return true for this query.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/12/08/q.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, edgeList = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]]
<strong>Output:</strong> [true,false]
<strong>Exaplanation:</strong> The above figure shows the given graph.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>2 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= edgeList.length, queries.length &lt;= 10<sup>5</sup></code></li><li><code>edgeList[i].length == 3</code></li><li><code>queries[j].length == 3</code></li><li><code>0 &lt;= u<sub>i</sub>, v<sub>i</sub>, p<sub>j</sub>, q<sub>j</sub>&nbsp;&lt;= n - 1</code></li><li><code>u<sub>i</sub>&nbsp;!= v<sub>i</sub></code></li><li><code>p<sub>j</sub>&nbsp;!= q<sub>j</sub></code></li><li><code>1 &lt;= dis<sub>i</sub>, limit<sub>j</sub>&nbsp;&lt;= 10<sup>9</sup></code></li><li>There may be&nbsp;<strong>multiple</strong>&nbsp;edges between two nodes.</li></ul>



<h2><strong>Solution: Union Find</strong></h2>



<p>Since queries are offline, we can reorder them to optimize time complexity. Answer queries by their limits in ascending order while union edges by weights up to the limit. In this case, we just need to go through the entire edge list at most once.</p>



<p>Time complexity: O(QlogQ + ElogE)<br>Space complexity: O(Q + E)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;bool&gt; distanceLimitedPathsExist(int n, vector&lt;vector&lt;int&gt;&gt;&amp; E, vector&lt;vector&lt;int&gt;&gt;&amp; Q) {
    vector&lt;int&gt; parents(n);
    iota(begin(parents), end(parents), 0);
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return parents[x] == x ? x : parents[x] = find(parents[x]);
    };
    const int m = Q.size();
    for (int i = 0; i &lt; m; ++i) Q[i].push_back(i);
    // Sort edges by weight in ascending order.
    sort(begin(E), end(E), [](const auto&amp; a, const auto&amp; b) { return a[2] &lt; b[2]; });
    // Sort queries by limit in ascending order
    sort(begin(Q), end(Q), [](const auto&amp; a, const auto&amp; b) { return a[2] &lt; b[2]; });
    vector&lt;bool&gt; ans(m);
    int i = 0;
    for (const auto&amp; q : Q) {      
      while (i &lt; E.size() &amp;&amp; E[i][2] &lt; q[2])
        parents[find(E[i++][0])] = find(E[i][1]);        
      ans[q[3]] = find(q[0]) == find(q[1]);
    }
    return ans;
  }
};</pre>
</div></div>



<p></p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1697-checking-existence-of-edge-length-limited-paths/">花花酱 LeetCode 1697. Checking Existence of Edge Length Limited Paths</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1697-checking-existence-of-edge-length-limited-paths/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1632. Rank Transform of a Matrix</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1632-rank-transform-of-a-matrix/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1632-rank-transform-of-a-matrix/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 29 Oct 2020 03:38:19 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[cc]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[matrix]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7570</guid>

					<description><![CDATA[<p>Given an&#160;m x n&#160;matrix, return&#160;a new matrix&#160;answer&#160;where&#160;answer[row][col]&#160;is the&#160;rank&#160;of&#160;matrix[row][col]. The&#160;rank&#160;is an&#160;integer&#160;that represents how large an element is compared to other elements. It is calculated using the&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1632-rank-transform-of-a-matrix/">花花酱 LeetCode 1632. Rank Transform of a Matrix</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Given an&nbsp;<code>m x n</code>&nbsp;<code>matrix</code>, return&nbsp;<em>a new matrix&nbsp;</em><code>answer</code><em>&nbsp;where&nbsp;</em><code>answer[row][col]</code><em>&nbsp;is the&nbsp;</em><em><strong>rank</strong>&nbsp;of&nbsp;</em><code>matrix[row][col]</code>.</p>



<p>The&nbsp;<strong>rank</strong>&nbsp;is an&nbsp;<strong>integer</strong>&nbsp;that represents how large an element is compared to other elements. It is calculated using the following rules:</p>



<ul><li>The rank is an integer starting from&nbsp;<code>1</code>.</li><li>If two elements&nbsp;<code>p</code>&nbsp;and&nbsp;<code>q</code>&nbsp;are in the&nbsp;<strong>same row or column</strong>, then:<ul><li>If&nbsp;<code>p &lt; q</code>&nbsp;then&nbsp;<code>rank(p) &lt; rank(q)</code></li><li>If&nbsp;<code>p == q</code>&nbsp;then&nbsp;<code>rank(p) == rank(q)</code></li><li>If&nbsp;<code>p &gt; q</code>&nbsp;then&nbsp;<code>rank(p) &gt; rank(q)</code></li></ul></li><li>The&nbsp;<strong>rank</strong>&nbsp;should be as&nbsp;<strong>small</strong>&nbsp;as possible.</li></ul>



<p>It is guaranteed that&nbsp;<code>answer</code>&nbsp;is unique under the given rules.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/18/rank1.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> matrix = [[1,2],[3,4]]
<strong>Output:</strong> [[1,2],[2,3]]
<strong>Explanation:</strong>
The rank of matrix[0][0] is 1 because it is the smallest integer in its row and column.
The rank of matrix[0][1] is 2 because matrix[0][1] &gt; matrix[0][0] and matrix[0][0] is rank 1.
The rank of matrix[1][0] is 2 because matrix[1][0] &gt; matrix[0][0] and matrix[0][0] is rank 1.
The rank of matrix[1][1] is 3 because matrix[1][1] &gt; matrix[0][1], matrix[1][1] &gt; matrix[1][0], and both matrix[0][1] and matrix[1][0] are rank 2.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/18/rank2.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> matrix = [[7,7],[7,7]]
<strong>Output:</strong> [[1,1],[1,1]]
</pre>



<p><strong>Example 3:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/18/rank3.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> matrix = [[20,-21,14],[-19,4,19],[22,-47,24],[-19,4,19]]
<strong>Output:</strong> [[4,2,3],[1,3,4],[5,1,6],[1,3,4]]
</pre>



<p><strong>Example 4:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/18/rank4.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> matrix = [[7,3,6],[1,4,5],[9,8,2]]
<strong>Output:</strong> [[5,1,4],[1,2,3],[6,3,1]]
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>m == matrix.length</code></li><li><code>n == matrix[i].length</code></li><li><code>1 &lt;= m, n &lt;= 500</code></li><li><code>-10<sup>9</sup>&nbsp;&lt;= matrix[row][col] &lt;= 10<sup>9</sup></code></li></ul>



<h2><strong>Solution: Union Find</strong></h2>



<p>Group cells by their values, process groups (cells that have the same value) in ascending order (smaller number has smaller rank).</p>



<p>For cells that are in the same row and same cols union them using union find, they should have the same rank which equals to max(max_rank_x[cols], max_rank_y[rows]) + 1.</p>



<p>Time complexity: O(m*n*(m+n))<br>Space complexity: O(m*n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class DSU {
public:
  DSU(int n): p_(n, -1) {}
  int find(int x) {
    return p_[x] == -1 ? x : p_[x] = find(p_[x]);
  }  
  void merge(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) p_[x] = y;    
  }
private:
  vector&lt;int&gt; p_;
};

class Solution {
public:
  vector&lt;vector&lt;int&gt;&gt; matrixRankTransform(vector&lt;vector&lt;int&gt;&gt;&amp; matrix) {
    const int m = matrix.size();
    const int n = matrix[0].size();
    vector&lt;vector&lt;int&gt;&gt; ans(m, vector&lt;int&gt;(n));
    map&lt;int, vector&lt;pair&lt;int, int&gt;&gt;&gt; mp; // val -&gt; {positions}
    for (int y = 0; y &lt; m; ++y)
      for (int x = 0; x &lt; n; ++x)
        mp[matrix[y][x]].emplace_back(x, y);
    vector&lt;int&gt; rx(n), ry(m);
    for (const auto&amp; [val, ps]: mp) {
      DSU dsu(n + m);
      vector&lt;vector&lt;pair&lt;int, int&gt;&gt;&gt; cc(n + m); // val -&gt; {positions}
      for (const auto&amp; [x, y]: ps)
        dsu.merge(x, y + n);
      for (const auto&amp; [x, y]: ps)        
        cc[dsu.find(x)].emplace_back(x, y);      
      for (const auto&amp; ps: cc) {
        int rank = 1;
        for (const auto&amp; [x, y]: ps)
          rank = max(rank, max(rx[x], ry[y]) + 1);
        for (const auto&amp; [x, y]: ps)
          rx[x] = ry[y] = ans[y][x] = rank;   
      }      
    }
    return ans;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1632-rank-transform-of-a-matrix/">花花酱 LeetCode 1632. Rank Transform of a Matrix</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1632-rank-transform-of-a-matrix/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1627. Graph Connectivity With Threshold</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1627-graph-connectivity-with-threshold/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1627-graph-connectivity-with-threshold/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 18 Oct 2020 19:40:14 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[factor]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7534</guid>

					<description><![CDATA[<p>We have&#160;n&#160;cities labeled from&#160;1&#160;to&#160;n. Two different cities with labels&#160;x&#160;and&#160;y&#160;are directly connected by a bidirectional road if and only if&#160;x&#160;and&#160;y&#160;share a common divisor&#160;strictly greater&#160;than some&#160;threshold. More&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1627-graph-connectivity-with-threshold/">花花酱 LeetCode 1627. Graph Connectivity With Threshold</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>We have&nbsp;<code>n</code>&nbsp;cities labeled from&nbsp;<code>1</code>&nbsp;to&nbsp;<code>n</code>. Two different cities with labels&nbsp;<code>x</code>&nbsp;and&nbsp;<code>y</code>&nbsp;are directly connected by a bidirectional road if and only if&nbsp;<code>x</code>&nbsp;and&nbsp;<code>y</code>&nbsp;share a common divisor&nbsp;<strong>strictly greater</strong>&nbsp;than some&nbsp;<code>threshold</code>. More formally, cities with labels&nbsp;<code>x</code>&nbsp;and&nbsp;<code>y</code>&nbsp;have a road between them if there exists an integer&nbsp;<code>z</code>&nbsp;such that all of the following are true:</p>



<ul><li><code>x % z == 0</code>,</li><li><code>y % z == 0</code>, and</li><li><code>z &gt; threshold</code>.</li></ul>



<p>Given the two integers,&nbsp;<code>n</code>&nbsp;and&nbsp;<code>threshold</code>, and an array of&nbsp;<code>queries</code>, you must determine for each&nbsp;<code>queries[i] = [a<sub>i</sub>, b<sub>i</sub>]</code>&nbsp;if cities&nbsp;<code>a<sub>i</sub></code>&nbsp;and&nbsp;<code>b<sub>i</sub></code>&nbsp;are connected (i.e. there is some path between them).</p>



<p>Return&nbsp;<em>an array&nbsp;</em><code>answer</code><em>, where&nbsp;</em><code>answer.length == queries.length</code><em>&nbsp;and&nbsp;</em><code>answer[i]</code><em>&nbsp;is&nbsp;</em><code>true</code><em>&nbsp;if for the&nbsp;</em><code>i<sup>th</sup></code><em>&nbsp;query, there is a path between&nbsp;</em><code>a<sub>i</sub></code><em>&nbsp;and&nbsp;</em><code>b<sub>i</sub></code><em>, or&nbsp;</em><code>answer[i]</code><em>&nbsp;is&nbsp;</em><code>false</code><em>&nbsp;if there is no path.</em></p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/09/ex1.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, threshold = 2, queries = [[1,4],[2,5],[3,6]]
<strong>Output:</strong> [false,false,true]
<strong>Explanation:</strong> The divisors for each number:
1:   1
2:   1, 2
3:   1, 3
4:   1, 2, 4
5:   1, 5
6:   1, 2, 3, 6
Using the underlined divisors above the threshold, only cities 3 and 6 share a common divisor, so they are the
only ones directly connected. The result of each query:
[1,4]   1 is not connected to 4
[2,5]   2 is not connected to 5
[3,6]   3 is connected to 6 through path 3--6
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/10/tmp.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, threshold = 0, queries = [[4,5],[3,4],[3,2],[2,6],[1,3]]
<strong>Output:</strong> [true,true,true,true,true]
<strong>Explanation:</strong> The divisors for each number are the same as the previous example. However, since the threshold is 0,
all divisors can be used. Since all numbers share 1 as a divisor, all cities are connected.
</pre>



<p><strong>Example 3:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/10/17/ex3.jpg" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, threshold = 1, queries = [[4,5],[4,5],[3,2],[2,3],[3,4]]
<strong>Output:</strong> [false,false,false,false,false]
<strong>Explanation:</strong> Only cities 2 and 4 share a common divisor 2 which is strictly greater than the threshold 1, so they are the only ones directly connected.
Please notice that there can be multiple queries for the same pair of nodes [x, y], and that the query [x, y] is equivalent to the query [y, x].
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>2 &lt;= n &lt;= 10<sup>4</sup></code></li><li><code>0 &lt;= threshold &lt;= n</code></li><li><code>1 &lt;= queries.length &lt;= 10<sup>5</sup></code></li><li><code>queries[i].length == 2</code></li><li><code>1 &lt;= a<sub>i</sub>, b<sub>i</sub>&nbsp;&lt;= cities</code></li><li><code>a<sub>i</sub>&nbsp;!= b<sub>i</sub></code></li></ul>



<h2><strong>Solution: Union Find</strong></h2>



<p>For x, merge 2x, 3x, 4x, ..,<br>If a number is already &#8220;merged&#8221;, skip it.</p>



<p>Time complexity: O(nlogn? + queries)? <br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;bool&gt; areConnected(int n, int threshold, vector&lt;vector&lt;int&gt;&gt;&amp; queries) {
    if (threshold == 0) return vector&lt;bool&gt;(queries.size(), true);
    
    vector&lt;int&gt; ds(n + 1);
    iota(begin(ds), end(ds), 0);
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return ds[x] == x ? x : ds[x] = find(ds[x]);
    };
    
    for (int x = threshold + 1; x &lt;= n; ++x)
      if (ds[x] == x)
        for (int y = 2 * x; y &lt;= n; y += x)    
          ds[max(find(x), find(y))] = min(find(x), find(y));
    
    vector&lt;bool&gt; ans;
    for (const vector&lt;int&gt;&amp; q : queries)
      ans.push_back(find(q[0]) == find(q[1]));    
    return ans;
  }
};</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag"># Author: Huahua
class Solution:
  def areConnected(self, n: int, threshold: int, 
                   queries: List[List[int]]) -&gt; List[bool]:
    if threshold == 0: return [True] * len(queries)
    
    ds = list(range(n + 1))
    def find(x: int) -&gt; int:
      if x != ds[x]: ds[x] = find(ds[x])
      return ds[x]

    for x in range(threshold + 1, n + 1):
      if ds[x] == x:
        for y in range(2 * x, n + 1, x):
          ds[max(find(x), find(y))] = min(find(x), find(y))

    return [find(x) == find(y) for x, y in queries]</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1627-graph-connectivity-with-threshold/">花花酱 LeetCode 1627. Graph Connectivity With Threshold</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1627-graph-connectivity-with-threshold/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1579. Remove Max Number of Edges to Keep Graph Fully Traversable</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1579-remove-max-number-of-edges-to-keep-graph-fully-traversable/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1579-remove-max-number-of-edges-to-keep-graph-fully-traversable/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 06 Sep 2020 15:29:51 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[spanning tree]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7354</guid>

					<description><![CDATA[<p>Alice and Bob have an undirected graph of&#160;n&#160;nodes&#160;and 3 types of edges: Type 1: Can be traversed by Alice only. Type 2: Can be traversed&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1579-remove-max-number-of-edges-to-keep-graph-fully-traversable/">花花酱 LeetCode 1579. Remove Max Number of Edges to Keep Graph Fully Traversable</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 1579. Remove Max Number of Edges to Keep Graph Fully Traversable - 刷题找工作 EP355" width="500" height="281" src="https://www.youtube.com/embed/eTQnRrmCWBc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>Alice and Bob have an undirected graph of&nbsp;<code>n</code>&nbsp;nodes&nbsp;and 3 types of edges:</p>



<ul><li>Type 1: Can be traversed by Alice only.</li><li>Type 2: Can be traversed by Bob only.</li><li>Type 3: Can by traversed by both Alice and Bob.</li></ul>



<p>Given an array&nbsp;<code>edges</code>&nbsp;where&nbsp;<code>edges[i] = [type<sub>i</sub>, u<sub>i</sub>, v<sub>i</sub>]</code>&nbsp;represents a bidirectional edge of type&nbsp;<code>type<sub>i</sub></code>&nbsp;between nodes&nbsp;<code>u<sub>i</sub></code>&nbsp;and&nbsp;<code>v<sub>i</sub></code>, find the maximum number of edges you can remove so that after removing the edges, the graph can still be fully traversed by both Alice and Bob. The graph is fully traversed by Alice and Bob if starting from any node, they can reach all other nodes.</p>



<p>Return&nbsp;<em>the maximum number of edges you can remove, or return</em>&nbsp;<code>-1</code>&nbsp;<em>if it&#8217;s impossible for the graph to be fully traversed by Alice and Bob.</em></p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/08/19/ex1.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
<strong>Output:</strong> 2
<strong>Explanation: </strong>If we remove the 2 edges [1,1,2] and [1,1,3]. The graph will still be fully traversable by Alice and Bob. Removing any additional edge will not make it so. So the maximum number of edges we can remove is 2.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/08/19/ex2.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
<strong>Output:</strong> 0
<strong>Explanation: </strong>Notice that removing any edge will not make the graph fully traversable by Alice and Bob.
</pre>



<p><strong>Example 3:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/08/19/ex3.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
<strong>Output:</strong> -1
<strong>Explanation: </strong>In the current graph, Alice cannot reach node 4 from the other nodes. Likewise, Bob cannot reach 1. Therefore it's impossible to make the graph fully traversable.</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= n &lt;= 10^5</code></li><li><code>1 &lt;= edges.length &lt;= min(10^5, 3 * n * (n-1) / 2)</code></li><li><code>edges[i].length == 3</code></li><li><code>1 &lt;= edges[i][0] &lt;= 3</code></li><li><code>1 &lt;= edges[i][1] &lt; edges[i][2] &lt;= n</code></li><li>All tuples&nbsp;<code>(type<sub>i</sub>, u<sub>i</sub>, v<sub>i</sub>)</code>&nbsp;are distinct.</li></ul>



<h2><strong>Solution: Greedy + Spanning Tree / Union Find</strong></h2>



<p>Use type 3 (both) edges first.</p>



<p>Time complexity: O(E)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">class DSU {
public: 
  DSU(int n): p_(n + 1), e_(0) {
    iota(begin(p_), end(p_), 0);
  }
  
  int find(int x) {
    if (p_[x] == x) return x;
    return p_[x] = find(p_[x]);    
  }
  
  int merge(int x, int y) {
    int rx = find(x);
    int ry = find(y);
    if (rx == ry) return 1;
    p_[rx] = ry;
    ++e_;
    return 0;
  }  
  
  int edges() const { return e_; }
private:
  vector&lt;int&gt; p_;
  int e_;
};

class Solution {
public:
  int maxNumEdgesToRemove(int n, vector&lt;vector&lt;int&gt;&gt;&amp; edges) {
    int ans = 0;
    DSU A(n), B(n);
    for (const auto&amp; e: edges) {
      if (e[0] != 3) continue;
      ans += A.merge(e[1], e[2]);
      B.merge(e[1], e[2]);
    }
    for (const auto&amp; e: edges) {
      if (e[0] == 3) continue;
      DSU&amp; d = e[0] == 1 ? A : B;
      ans += d.merge(e[1], e[2]);
    }
    return (A.edges() == n - 1 &amp;&amp; B.edges() == n - 1) ? ans : -1;
  }
};</pre>

</div><h2 class="tabtitle">python3</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">class DSU:
  def __init__(self, n: int):
    self.p = list(range(n))
    self.e = 0
    
  def find(self, x: int) -&gt; int:
    if x != self.p[x]: self.p[x] = self.find(self.p[x])
    return self.p[x]
  
  def merge(self, x: int, y: int) -&gt; int:
    rx, ry = self.find(x), self.find(y)
    if rx == ry: return 1
    self.p[rx] = ry
    self.e += 1
    return 0
  
class Solution:
  def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -&gt; int:
    A, B = DSU(n + 1), DSU(n + 1)    
    ans = 0
    for t, x, y in edges:
      if t != 3: continue
      ans += A.merge(x, y)
      B.merge(x, y)
    for t, x, y in edges:
      if t == 3: continue
      d = A if t == 1 else B
      ans += d.merge(x, y)
    return ans if A.e == B.e == n - 1 else -1</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1579-remove-max-number-of-edges-to-keep-graph-fully-traversable/">花花酱 LeetCode 1579. Remove Max Number of Edges to Keep Graph Fully Traversable</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1579-remove-max-number-of-edges-to-keep-graph-fully-traversable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 27 Jun 2020 05:33:39 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[MST]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=6962</guid>

					<description><![CDATA[<p>Given a weighted undirected connected graph with&#160;n&#160;vertices numbered from&#160;0&#160;to&#160;n-1,&#160;and an array&#160;edges&#160;where&#160;edges[i] = [fromi, toi, weighti]&#160;represents a bidirectional and weighted edge between nodes&#160;fromi&#160;and&#160;toi. A minimum spanning&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/">花花酱 LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree - 刷题找工作 EP338" width="500" height="281" src="https://www.youtube.com/embed/GzPUvV85kBI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>Given a weighted undirected connected graph with&nbsp;<code>n</code>&nbsp;vertices numbered from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>n-1</code>,&nbsp;and an array&nbsp;<code>edges</code>&nbsp;where&nbsp;<code>edges[i] = [from<sub>i</sub>, to<sub>i</sub>, weight<sub>i</sub>]</code>&nbsp;represents a bidirectional and weighted edge between nodes&nbsp;<code>from<sub>i</sub></code>&nbsp;and&nbsp;<code>to<sub>i</sub></code>. A minimum spanning tree (MST) is a subset of the edges of the graph that connects all vertices without cycles&nbsp;and with the minimum possible total edge weight.</p>



<p>Find&nbsp;<em>all the critical and pseudo-critical edges in the minimum spanning tree (MST) of the given graph</em>. An MST edge whose deletion from the graph would cause the MST weight to increase is called a&nbsp;<em>critical edge</em>. A&nbsp;<em>pseudo-critical edge</em>, on the other hand, is that which can appear in some MSTs but not all.</p>



<p>Note that you can return the indices of the edges in any order.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/06/04/ex1.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, edges = [[0,1,1],[1,2,1],[2,3,2],[0,3,2],[0,4,3],[3,4,3],[1,4,6]]
<strong>Output:</strong> [[0,1],[2,3,4,5]]
<strong>Explanation:</strong> The figure above describes the graph.
The following figure shows all the possible MSTs:

Notice that the two edges 0 and 1 appear in all MSTs, therefore they are critical edges, so we return them in the first list of the output.
The edges 2, 3, 4, and 5 are only part of some MSTs, therefore they are considered pseudo-critical edges. We add them to the second list of the output.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/06/04/ex2.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, edges = [[0,1,1],[1,2,1],[2,3,1],[0,3,1]]
<strong>Output:</strong> [[],[0,1,2,3]]
<strong>Explanation:</strong> We can observe that since all 4 edges have equal weight, choosing any 3 edges from the given 4 will yield an MST. Therefore all 4 edges are pseudo-critical.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>2 &lt;= n &lt;= 100</code></li><li><code>1 &lt;= edges.length &lt;= min(200, n * (n - 1) / 2)</code></li><li><code>edges[i].length == 3</code></li><li><code>0 &lt;= from<sub>i</sub>&nbsp;&lt; to<sub>i</sub>&nbsp;&lt; n</code></li><li><code>1 &lt;= weight<sub>i</sub>&nbsp;&lt;= 1000</code></li><li>All pairs&nbsp;<code>(from<sub>i</sub>, to<sub>i</sub>)</code>&nbsp;are distinct.</li></ul>



<h2><strong>Solution: Brute Force?</strong></h2>



<figure class="wp-block-image size-large"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/06/1489-ep338.png" alt="" class="wp-image-6967" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/06/1489-ep338.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/06/1489-ep338-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/06/1489-ep338-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<p>For each edge<br>1. exclude it and build a MST, cost increased =&gt; critical<br>2. for a non critical edge, force include it and build a MST, cost remains the same =&gt; pseudo critical</p>



<p>Proof of 2, if a non critical / non pseudo critical edge was added into the MST, the total cost must be increased. So if the cost remains the same, must be the other case. Since we know the edge is non-critical, so it has to be pseudo critical.</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class UnionFind {
 public:
  explicit UnionFind(int n): p_(n), r_(n) { iota(begin(p_), end(p_), 0); } // e.g. p[i] = i
  int Find(int x) { return p_[x] == x ? x : p_[x] = Find(p_[x]); }
  bool Union(int x, int y) {
    int rx = Find(x);
    int ry = Find(y);
    if (rx == ry) return false;
    if (r_[rx] == r_[ry]) {
      p_[rx] = ry;
      ++r_[ry];
    } else if (r_[rx] &gt; r_[ry]) {
      p_[ry] = rx;
    } else {
      p_[rx] = ry;
    }    
    return true;
  }
 private:
  vector&lt;int&gt; p_, r_;  
};

class Solution {
public:
  vector&lt;vector&lt;int&gt;&gt; findCriticalAndPseudoCriticalEdges(int n, vector&lt;vector&lt;int&gt;&gt;&amp; edges) {
    // Record the original id.
    for (int i = 0; i &lt; edges.size(); ++i) edges[i].push_back(i);
    // Sort edges by weight.
    sort(begin(edges), end(edges), [&amp;](const auto&amp; e1, const auto&amp; e2){
      if (e1[2] != e2[2]) return e1[2] &lt; e2[2];        
      return e1 &lt; e2;
    });
    // Cost of MST, ex: edge to exclude, in: edge to include.
    auto MST = [&amp;](int ex = -1, int in = -1) -&gt; int {
      UnionFind uf(n);
      int cost = 0;
      int count = 0;
      if (in &gt;= 0) {
        cost += edges[in][2];
        uf.Union(edges[in][0], edges[in][1]);
        count++;
      }
      for (int i = 0; i &lt; edges.size(); ++i) {        
        if (i == ex) continue;
        if (!uf.Union(edges[i][0], edges[i][1])) continue;
        cost += edges[i][2];
        ++count;
      }
      return count == n - 1 ? cost : INT_MAX;
    };
    const int min_cost = MST();
    vector&lt;int&gt; criticals;
    vector&lt;int&gt; pseudos;
    for (int i = 0; i &lt; edges.size(); ++i) {
      // Cost increased or can't form a tree.
      if (MST(i) &gt; min_cost) {
        criticals.push_back(edges[i][3]);
      } else if (MST(-1, i) == min_cost) {
        pseudos.push_back(edges[i][3]);
      }
    }
    return {criticals, pseudos};
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/">花花酱 LeetCode 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 721. Accounts Merge</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-721-accounts-merge/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-721-accounts-merge/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 30 Jan 2020 05:04:01 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=6182</guid>

					<description><![CDATA[<p>Given a list&#160;accounts, each element&#160;accounts[i]&#160;is a list of strings, where the first element&#160;accounts[i][0]&#160;is a&#160;name, and the rest of the elements are&#160;emails&#160;representing emails of the account.&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-721-accounts-merge/">花花酱 LeetCode 721. Accounts Merge</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Given a list&nbsp;<code>accounts</code>, each element&nbsp;<code>accounts[i]</code>&nbsp;is a list of strings, where the first element&nbsp;<code>accounts[i][0]</code>&nbsp;is a&nbsp;<em>name</em>, and the rest of the elements are&nbsp;<em>emails</em>&nbsp;representing emails of the account.</p>



<p>Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.</p>



<p>After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails&nbsp;<strong>in sorted order</strong>. The accounts themselves can be returned in any order.</p>



<p><strong>Example 1:</strong><br></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> 
accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
<strong>Output:</strong> [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
<strong>Explanation:</strong> 
The first and third John's are the same person as they have the common email "johnsmith@mail.com".
The second John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], 
['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
</pre>



<p><strong>Note:</strong>The length of&nbsp;<code>accounts</code>&nbsp;will be in the range&nbsp;<code>[1, 1000]</code>.The length of&nbsp;<code>accounts[i]</code>&nbsp;will be in the range&nbsp;<code>[1, 10]</code>.The length of&nbsp;<code>accounts[i][j]</code>&nbsp;will be in the range&nbsp;<code>[1, 30]</code>.</p>



<h2><strong>Solution: Union-Find</strong></h2>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;vector&lt;string&gt;&gt; accountsMerge(vector&lt;vector&lt;string&gt;&gt;&amp; accounts) {
    unordered_map&lt;string_view, int&gt; ids;   // email to id
    unordered_map&lt;int, string_view&gt; names; // id to name
    vector&lt;int&gt; p(10000);
    iota(begin(p), end(p), 0);
    
    function&lt;int(int)&gt; find = [&amp;](int x) {
      if (p[x] != x) p[x] = find(p[x]);
      return p[x];
    };
    
    auto getIdByEmail = [&amp;](string_view email) {
      auto it = ids.find(email);
      if (it == ids.end()) {
        int id = ids.size();
        return ids[email] = id;
      }
      return it-&gt;second;
    };

    for (const auto&amp; account : accounts) {      
      int u = find(getIdByEmail(account[1]));      
      for (int i = 2; i &lt; account.size(); ++i) 
        p[find(u)] = find(getIdByEmail(account[i]));      
      names[find(u)] = string_view(account[0]);
    }

    unordered_map&lt;int, set&lt;string&gt;&gt; mergered;
    for (const auto&amp; account : accounts)
      for (int i = 1; i &lt; account.size(); ++i) {
        int id = find(getIdByEmail(account[i]));
        mergered[id].insert(account[i]);
      }    

    vector&lt;vector&lt;string&gt;&gt; ans;
    for (const auto&amp; kv : mergered) {
      ans.push_back({string(names[kv.first])});
      ans.back().insert(ans.back().end(), kv.second.begin(), kv.second.end());
    }

    return ans;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-721-accounts-merge/">花花酱 LeetCode 721. Accounts Merge</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-721-accounts-merge/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1319. Number of Operations to Make Network Connected</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1319-number-of-operations-to-make-network-connected/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1319-number-of-operations-to-make-network-connected/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 12 Jan 2020 06:15:27 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[O(V+E)]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=6077</guid>

					<description><![CDATA[<p>There are&#160;n&#160;computers numbered from&#160;0&#160;to&#160;n-1&#160;connected by&#160;ethernet cables&#160;connections&#160;forming a network where&#160;connections[i] = [a, b]&#160;represents a connection between computers&#160;a&#160;and&#160;b. Any computer&#160;can reach any other computer directly or indirectly&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1319-number-of-operations-to-make-network-connected/">花花酱 LeetCode 1319. Number of Operations to Make Network Connected</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 1319. Number of Operations to Make Network Connected - 刷题找工作 EP297" width="500" height="281" src="https://www.youtube.com/embed/8d8vfU3LYHM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>There are&nbsp;<code>n</code>&nbsp;computers numbered from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>n-1</code>&nbsp;connected by&nbsp;ethernet cables&nbsp;<code>connections</code>&nbsp;forming a network where&nbsp;<code>connections[i] = [a, b]</code>&nbsp;represents a connection between computers&nbsp;<code>a</code>&nbsp;and&nbsp;<code>b</code>. Any computer&nbsp;can reach any other computer directly or indirectly through the network.</p>



<p>Given an initial computer network&nbsp;<code>connections</code>. You can extract certain cables between two directly connected computers, and place them between any pair of disconnected computers to make them directly connected. Return the&nbsp;<em>minimum number of times</em>&nbsp;you need to do this in order to make all the computers connected. If it&#8217;s not possible, return -1.&nbsp;</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/01/02/sample_1_1677.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4, connections = [[0,1],[0,2],[1,2]]
<strong>Output:</strong> 1
<strong>Explanation:</strong> Remove cable between computer 1 and 2 and place between computers 1 and 3.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img src="https://assets.leetcode.com/uploads/2020/01/02/sample_2_1677.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]]
<strong>Output:</strong> 2
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 6, connections = [[0,1],[0,2],[0,3],[1,2]]
<strong>Output:</strong> -1
<strong>Explanation:</strong> There are not enough cables.
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 5, connections = [[0,1],[0,2],[3,4],[2,3]]
<strong>Output:</strong> 0
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= n &lt;= 10^5</code></li><li><code>1 &lt;= connections.length &lt;= min(n*(n-1)/2, 10^5)</code></li><li><code>connections[i].length == 2</code></li><li><code>0 &lt;= connections[i][0], connections[i][1]&nbsp;&lt; n</code></li><li><code>connections[i][0] != connections[i][1]</code></li><li>There are no repeated connections.</li><li>No two computers are connected by more than one cable.</li></ul>



<h2><strong>Solution 1: Union-Find</strong></h2>



<p>Time complexity: O(V+E)<br>Space complexity: O(V)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  int makeConnected(int n, vector&lt;vector&lt;int&gt;&gt;&amp; connections) {
    if (connections.size() &lt; n - 1) return -1;
    vector&lt;int&gt; p(n);
    iota(begin(p), end(p), 0);
    
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return p[x] == x ? x : p[x] = find(p[x]);
    };
    
    for (const auto&amp; c : connections)
      p[find(c[0])] = find(c[1]);    
    
    unordered_set&lt;int&gt; s;
    for (int i = 0; i &lt; n; ++i)
      s.insert(find(i));
    
    return s.size() - 1;        
  }
};</pre>
</div></div>



<h2><strong>Solution 2: DFS</strong></h2>



<p>Time complexity: O(V+E)<br>Space complexity: O(V+E)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  int makeConnected(int n, vector&lt;vector&lt;int&gt;&gt;&amp; connections) {
    if (connections.size() &lt; n - 1) return -1;
    vector&lt;vector&lt;int&gt;&gt; g(n);
    for (const auto&amp; c : connections) {
      g[c[0]].push_back(c[1]);
      g[c[1]].push_back(c[0]);
    }
    vector&lt;int&gt; seen(n);
    int count = 0;
    function&lt;void(int)&gt; dfs = [&amp;](int cur) {
      for (int nxt : g[cur])
        if (!seen[nxt]++) dfs(nxt);      
    };
    for (int i = 0; i &lt; n; ++i)
      if (!seen[i]++ &amp;&amp; ++count)
        dfs(i);        
    return count - 1;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1319-number-of-operations-to-make-network-connected/">花花酱 LeetCode 1319. Number of Operations to Make Network Connected</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1319-number-of-operations-to-make-network-connected/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1202. Smallest String With Swaps</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 22 Sep 2019 09:18:15 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[connected components]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=5573</guid>

					<description><![CDATA[<p>You are given a string&#160;s, and an array of pairs of indices in the string&#160;pairs&#160;where&#160;pairs[i] =&#160;[a, b]&#160;indicates 2 indices(0-indexed) of the string. You can&#160;swap the&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/">花花酱 LeetCode 1202. Smallest String With Swaps</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe width="500" height="375" src="https://www.youtube.com/embed/qosJ4632QAg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>You are given a string&nbsp;<code>s</code>, and an array of pairs of indices in the string&nbsp;<code>pairs</code>&nbsp;where&nbsp;<code>pairs[i] =&nbsp;[a, b]</code>&nbsp;indicates 2 indices(0-indexed) of the string.</p>



<p>You can&nbsp;swap the characters at any pair of indices in the given&nbsp;<code>pairs</code>&nbsp;<strong>any number of times</strong>.</p>



<p>Return the&nbsp;lexicographically smallest string that&nbsp;<code>s</code>&nbsp;can be changed to after using the swaps.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "dcab", pairs = [[0,3],[1,2]]
<strong>Output:</strong> "bacd"
<strong>Explaination:</strong> 
Swap s[0] and s[3], s = "bcad"
Swap s[1] and s[2], s = "bacd"
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "dcab", pairs = [[0,3],[1,2],[0,2]]
<strong>Output:</strong> "abcd"
<strong>Explaination: </strong>
Swap s[0] and s[3], s = "bcad"
Swap s[0] and s[2], s = "acbd"
Swap s[1] and s[2], s = "abcd"</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "cba", pairs = [[0,1],[1,2]]
<strong>Output:</strong> "abc"
<strong>Explaination: </strong>
Swap s[0] and s[1], s = "bca"
Swap s[1] and s[2], s = "bac"
Swap s[0] and s[1], s = "abc"

</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= s.length &lt;= 10^5</code></li><li><code>0 &lt;= pairs.length &lt;= 10^5</code></li><li><code>0 &lt;= pairs[i][0], pairs[i][1] &lt;&nbsp;s.length</code></li><li><code>s</code>&nbsp;only contains lower case English letters.</li></ul>



<h2><strong>Solution: Connected Components</strong></h2>



<figure class="wp-block-image"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/09/1202-ep271.png" alt="" class="wp-image-5587" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/09/1202-ep271.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/09/1202-ep271-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/09/1202-ep271-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<p>Use DFS / Union-Find to find all the connected components of swapable indices. For each connected components (index group), extract the subsequence of corresponding chars as a string, sort it and put it back to the original string in the same location.</p>



<p>e.g. s = &#8220;dcab&#8221;, pairs = [[0,3],[1,2]]<br>There are two connected components: {0,3}, {1,2}<br>subsequences: <br>1. 0,3 &#8220;db&#8221;, sorted: &#8220;bd&#8221;<br>2. 1,2 &#8220;ca&#8221;, sorted: &#8220;ac&#8221;<br>0 =&gt; b<br>1 =&gt; a<br>2 =&gt; c<br>3 =&gt; d<br>final = &#8220;bacd&#8221;<br></p>



<p>Time complexity: DFS: O(nlogn + k*(V+E)), Union-Find: O(nlogn + V+E)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++/DFS</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, 268 ms, 89 MB
class Solution {
public:
  string smallestStringWithSwaps(string s, vector&lt;vector&lt;int&gt;&gt;&amp; pairs) {
    vector&lt;vector&lt;int&gt;&gt; g(s.length());
    for (const auto&amp; e : pairs) {
      g[e[0]].push_back(e[1]);
      g[e[1]].push_back(e[0]);
    }

    unordered_set&lt;int&gt; seen;
    vector&lt;int&gt; idx;
    string tmp;
    function&lt;void(int)&gt; dfs = [&amp;](int cur) {
      if (seen.count(cur)) return;
      seen.insert(cur);
      idx.push_back(cur);
      tmp += s[cur];
      for (int nxt : g[cur]) dfs(nxt);
    };

    for (int i = 0; i &lt; s.length(); ++i) {
      if (seen.count(i)) continue;
      idx.clear();
      tmp.clear();
      dfs(i);
      sort(begin(tmp), end(tmp));
      sort(begin(idx), end(idx));      
      for (int k = 0; k &lt; idx.size(); ++k)
        s[idx[k]] = tmp[k];
    }
    return s;
  }
};</pre>

</div><h2 class="tabtitle">C++/Union-Find</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, 152 ms, 48.2 MB
class Solution {
public:
  string smallestStringWithSwaps(string s, vector&lt;vector&lt;int&gt;&gt;&amp; pairs) {
    int n = s.length();
    vector&lt;int&gt; p(n);    
    iota(begin(p), end(p), 0); // p = {0, 1, 2, ... n - 1}
    
    function&lt;int(int)&gt; find = [&amp;](int x) {
      return p[x] == x ? x : p[x] = find(p[x]);
    };        
    
    for (const auto&amp; e : pairs)
      p[find(e[0])] = find(e[1]); // union
    
    vector&lt;vector&lt;int&gt;&gt; idx(n);
    vector&lt;string&gt; ss(n);
    
    for (int i = 0; i &lt; s.length(); ++i) {
      int id = find(i);      
      idx[id].push_back(i); // already sorted
      ss[id].push_back(s[i]);
    }
    
    for (int i = 0; i &lt; n; ++i) {      
      sort(begin(ss[i]), end(ss[i]));
      for (int k = 0; k &lt; idx[i].size(); ++k)
        s[idx[i][k]] = ss[i][k];
    }
    
    return s;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/">花花酱 LeetCode 1202. Smallest String With Swaps</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-1202-smallest-string-with-swaps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 990. Satisfiability of Equality Equations</title>
		<link>https://zxi.mytechroad.com/blog/graph/leetcode-990-satisfiability-of-equality-equations/</link>
					<comments>https://zxi.mytechroad.com/blog/graph/leetcode-990-satisfiability-of-equality-equations/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 10 Feb 2019 10:21:32 +0000</pubDate>
				<category><![CDATA[Graph]]></category>
		<category><![CDATA[equation]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=4824</guid>

					<description><![CDATA[<p>Given an array&#160;equations&#160;of strings that represent relationships between variables, each string&#160;equations[i]&#160;has length&#160;4&#160;and takes one of two different forms:&#160;"a==b"&#160;or&#160;"a!=b".&#160; Here,&#160;a&#160;and&#160;b&#160;are lowercase letters (not necessarily different) that&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-990-satisfiability-of-equality-equations/">花花酱 LeetCode 990. Satisfiability of Equality Equations</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode Weekly Contest 123 (989, 990, 991, 992) - 刷题找工作" width="500" height="375" src="https://www.youtube.com/embed/FZPtxuxArLU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>Given an array&nbsp;equations&nbsp;of strings that represent relationships between variables, each string&nbsp;<code>equations[i]</code>&nbsp;has length&nbsp;<code>4</code>&nbsp;and takes one of two different forms:&nbsp;<code>"a==b"</code>&nbsp;or&nbsp;<code>"a!=b"</code>.&nbsp; Here,&nbsp;<code>a</code>&nbsp;and&nbsp;<code>b</code>&nbsp;are lowercase letters (not necessarily different) that represent one-letter variable names.</p>



<p>Return&nbsp;<code>true</code>&nbsp;if and only if it is possible to assign integers to variable names&nbsp;so as to satisfy all the given equations.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>["a==b","b!=a"]
<strong>Output: </strong>false
<strong>Explanation: </strong>If we assign say, a = 1 and b = 1, then the first equation is satisfied, but not the second.  There is no way to assign the variables to satisfy both equations.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>["b==a","a==b"]
<strong>Output: </strong>true
<strong>Explanation: </strong>We could assign a = 1 and b = 1 to satisfy both equations.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>["a==b","b==c","a==c"]
<strong>Output: </strong>true
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>["a==b","b!=c","c==a"]
<strong>Output: </strong>false
</pre>



<p><strong>Example 5:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>["c==c","b==d","x!=z"]
<strong>Output: </strong>true
</pre>



<p><strong>Note:</strong></p>



<ol><li><code>1 &lt;= equations.length &lt;= 500</code></li><li><code>equations[i].length == 4</code></li><li><code>equations[i][0]</code>&nbsp;and&nbsp;<code>equations[i][3]</code>&nbsp;are lowercase letters</li><li><code>equations[i][1]</code>&nbsp;is either&nbsp;<code>'='</code>&nbsp;or&nbsp;<code>'!'</code></li><li><code>equations[i][2]</code>&nbsp;is&nbsp;<code>'='</code></li></ol>



<h2><strong>Solution: Union Find</strong></h2>



<p>Time complexity: O(n)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, running time: 12 ms, 7.1 MB
class Solution {
public:
  bool equationsPossible(vector&lt;string&gt;&amp; equations) {        
    iota(begin(parents_), end(parents_), 0);    
    for (const auto&amp; eq : equations)     
      if (eq[1] == '=')
        parents_[find(eq[0])] = find(eq[3]);
    for (const auto&amp; eq : equations)     
      if (eq[1] == '!' &amp;&amp; find(eq[0]) == find(eq[3]))        
          return false;
    return true;
  }
private:
  array&lt;int, 128&gt; parents_;
  int find(int x) {
    if (x != parents_[x])
      parents_[x] = find(parents_[x]);
    return parents_[x];
  }  
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/graph/leetcode-990-satisfiability-of-equality-equations/">花花酱 LeetCode 990. Satisfiability of Equality Equations</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/graph/leetcode-990-satisfiability-of-equality-equations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
