<?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>Data Structure &#8211; Huahua&#8217;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/category/data-structure/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog</link>
	<description></description>
	<lastBuildDate>Mon, 04 Apr 2022 02:22:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.4</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>Data Structure &#8211; Huahua&#8217;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 2227. Encrypt and Decrypt Strings</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-2227-encrypt-and-decrypt-strings/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-2227-encrypt-and-decrypt-strings/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 03 Apr 2022 09:39:44 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[dictionary]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[string]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9626</guid>

					<description><![CDATA[You are given a character array&#160;keys&#160;containing&#160;unique&#160;characters and a string array&#160;values&#160;containing strings of length 2. You are also given another string array&#160;dictionary&#160;that contains all permitted original&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given a character array&nbsp;<code>keys</code>&nbsp;containing&nbsp;<strong>unique</strong>&nbsp;characters and a string array&nbsp;<code>values</code>&nbsp;containing strings of length 2. You are also given another string array&nbsp;<code>dictionary</code>&nbsp;that contains all permitted original strings after decryption. You should implement a data structure that can encrypt or decrypt a&nbsp;<strong>0-indexed</strong>&nbsp;string.</p>



<p>A string is&nbsp;<strong>encrypted</strong>&nbsp;with the following process:</p>



<ol class="wp-block-list"><li>For each character&nbsp;<code>c</code>&nbsp;in the string, we find the index&nbsp;<code>i</code>&nbsp;satisfying&nbsp;<code>keys[i] == c</code>&nbsp;in&nbsp;<code>keys</code>.</li><li>Replace&nbsp;<code>c</code>&nbsp;with&nbsp;<code>values[i]</code>&nbsp;in the string.</li></ol>



<p>A string is&nbsp;<strong>decrypted</strong>&nbsp;with the following process:</p>



<ol class="wp-block-list"><li>For each substring&nbsp;<code>s</code>&nbsp;of length 2 occurring at an even index in the string, we find an&nbsp;<code>i</code>&nbsp;such that&nbsp;<code>values[i] == s</code>. If there are multiple valid&nbsp;<code>i</code>, we choose&nbsp;<strong>any</strong>&nbsp;one of them. This means a string could have multiple possible strings it can decrypt to.</li><li>Replace&nbsp;<code>s</code>&nbsp;with&nbsp;<code>keys[i]</code>&nbsp;in the string.</li></ol>



<p>Implement the&nbsp;<code>Encrypter</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>Encrypter(char[] keys, String[] values, String[] dictionary)</code>&nbsp;Initializes the&nbsp;<code>Encrypter</code>&nbsp;class with&nbsp;<code>keys, values</code>, and&nbsp;<code>dictionary</code>.</li><li><code>String encrypt(String word1)</code>&nbsp;Encrypts&nbsp;<code>word1</code>&nbsp;with the encryption process described above and returns the encrypted string.</li><li><code>int decrypt(String word2)</code>&nbsp;Returns the number of possible strings&nbsp;<code>word2</code>&nbsp;could decrypt to that also appear in&nbsp;<code>dictionary</code>.</li></ul>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input</strong>
["Encrypter", "encrypt", "decrypt"]
[[['a', 'b', 'c', 'd'], ["ei", "zf", "ei", "am"], ["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"]], ["abcd"], ["eizfeiam"]]
<strong>Output</strong>
</pre>


<p>[null, &#8220;eizfeiam&#8221;, 2]</p>



<p><strong>Explanation</strong> Encrypter encrypter = new Encrypter([[&#8216;a&#8217;, &#8216;b&#8217;, &#8216;c&#8217;, &#8216;d&#8217;], [&#8220;ei&#8221;, &#8220;zf&#8221;, &#8220;ei&#8221;, &#8220;am&#8221;], [&#8220;abcd&#8221;, &#8220;acbd&#8221;, &#8220;adbc&#8221;, &#8220;badc&#8221;, &#8220;dacb&#8221;, &#8220;cadb&#8221;, &#8220;cbda&#8221;, &#8220;abad&#8221;]); encrypter.encrypt(&#8220;abcd&#8221;); // return &#8220;eizfeiam&#8221;. &nbsp; // &#8216;a&#8217; maps to &#8220;ei&#8221;, &#8216;b&#8217; maps to &#8220;zf&#8221;, &#8216;c&#8217; maps to &#8220;ei&#8221;, and &#8216;d&#8217; maps to &#8220;am&#8221;. encrypter.decrypt(&#8220;eizfeiam&#8221;); // return 2. // &#8220;ei&#8221; can map to &#8216;a&#8217; or &#8216;c&#8217;, &#8220;zf&#8221; maps to &#8216;b&#8217;, and &#8220;am&#8221; maps to &#8216;d&#8217;. // Thus, the possible strings after decryption are &#8220;abad&#8221;, &#8220;cbad&#8221;, &#8220;abcd&#8221;, and &#8220;cbcd&#8221;. // 2 of those strings, &#8220;abad&#8221; and &#8220;abcd&#8221;, appear in dictionary, so the answer is 2.</p>



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



<ul class="wp-block-list"><li><code>1 &lt;= keys.length == values.length &lt;= 26</code></li><li><code>values[i].length == 2</code></li><li><code>1 &lt;= dictionary.length &lt;= 100</code></li><li><code>1 &lt;= dictionary[i].length &lt;= 100</code></li><li>All&nbsp;<code>keys[i]</code>&nbsp;and&nbsp;<code>dictionary[i]</code>&nbsp;are&nbsp;<strong>unique</strong>.</li><li><code>1 &lt;= word1.length &lt;= 2000</code></li><li><code>1 &lt;= word2.length &lt;= 200</code></li><li>All&nbsp;<code>word1[i]</code>&nbsp;appear in&nbsp;<code>keys</code>.</li><li><code>word2.length</code>&nbsp;is even.</li><li><code>keys</code>,&nbsp;<code>values[i]</code>,&nbsp;<code>dictionary[i]</code>,&nbsp;<code>word1</code>, and&nbsp;<code>word2</code>&nbsp;only contain lowercase English letters.</li><li>At most&nbsp;<code>200</code>&nbsp;calls will be made to&nbsp;<code>encrypt</code>&nbsp;and&nbsp;<code>decrypt</code>&nbsp;<strong>in total</strong>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: </strong></h2>



<p>For encryption, follow the instruction. Time complexity: O(len(word)) = O(2000)<br>For decryption, try all words in the dictionary and encrypt them and compare the encrypted string with the word to decrypt. Time <meta charset="utf-8">complexity: O(sum(len(word_in_dict))) = O(100*100)</p>



<p>Worst case: 200 calls to decryption, T = 200 * O(100 * 100) = O(2*10<sup>6</sup>)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Encrypter {
public:
  Encrypter(vector&lt;char&gt;&amp; keys, 
            vector&lt;string&gt;&amp; values, 
            vector&lt;string&gt;&amp; dictionary):
        vals(26),
        dict(dictionary) {
    for (size_t i = 0; i &lt; keys.size(); ++i)
      vals[keys[i] - 'a'] = values[i];  
  }

  string encrypt(string word1) {
    string ans;
    for (char c : word1)
      ans += vals[c - 'a'];
    return ans;
  }

  int decrypt(string word2) {
    return count_if(begin(dict), end(dict), [&amp;](const string&amp; w){ 
      return encrypt(w) == word2;
    });    
  }
private:
  vector&lt;string&gt; vals;
  vector&lt;string&gt; dict;
};</pre>
</div></div>



<h2 class="wp-block-heading"><strong>Optimization</strong></h2>



<p>Pre-compute answer for all the words in dictionary.</p>



<p>decrypt: Time complexity: O(1)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Encrypter {
public:
  Encrypter(vector&lt;char&gt;&amp; keys, 
            vector&lt;string&gt;&amp; values, 
            vector&lt;string&gt;&amp; dictionary):
        vals(26) {
    for (size_t i = 0; i &lt; keys.size(); ++i)
      vals[keys[i] - 'a'] = values[i];  
    for (const string&amp; w : dictionary)
      ++counts[encrypt(w)];
  }

  string encrypt(string word1) {
    string ans;
    for (char c : word1)
      ans += vals[c - 'a'];
    return ans;
  }

  int decrypt(string word2) {
    auto it = counts.find(word2);
    return it == counts.end() ? 0 : it-&gt;second;
  }
private:
  vector&lt;string&gt; vals;  
  unordered_map&lt;string, int&gt; counts;
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-2227-encrypt-and-decrypt-strings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1912. Design Movie Rental System</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-1912-design-movie-rental-system/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-1912-design-movie-rental-system/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 01 Jan 2022 23:40:32 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[hashtable]]></category>
		<category><![CDATA[treeset]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9387</guid>

					<description><![CDATA[You have a movie renting company consisting of&#160;n&#160;shops. You want to implement a renting system that supports searching for, booking, and returning movies. The system&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You have a movie renting company consisting of&nbsp;<code>n</code>&nbsp;shops. You want to implement a renting system that supports searching for, booking, and returning movies. The system should also support generating a report of the currently rented movies.</p>



<p>Each movie is given as a 2D integer array&nbsp;<code>entries</code>&nbsp;where&nbsp;<code>entries[i] = [shop<sub>i</sub>, movie<sub>i</sub>, price<sub>i</sub>]</code>&nbsp;indicates that there is a copy of movie&nbsp;<code>movie<sub>i</sub></code>&nbsp;at shop&nbsp;<code>shop<sub>i</sub></code>&nbsp;with a rental price of&nbsp;<code>price<sub>i</sub></code>. Each shop carries&nbsp;<strong>at most one</strong>&nbsp;copy of a movie&nbsp;<code>movie<sub>i</sub></code>.</p>



<p>The system should support the following functions:</p>



<ul class="wp-block-list"><li><strong>Search</strong>: Finds the&nbsp;<strong>cheapest 5 shops</strong>&nbsp;that have an&nbsp;<strong>unrented copy</strong>&nbsp;of a given movie. The shops should be sorted by&nbsp;<strong>price</strong>&nbsp;in ascending order, and in case of a tie, the one with the&nbsp;<strong>smaller&nbsp;</strong><code>shop<sub>i</sub></code>&nbsp;should appear first. If there are less than 5 matching shops, then all of them should be returned. If no shop has an unrented copy, then an empty list should be returned.</li><li><strong>Rent</strong>: Rents an&nbsp;<strong>unrented copy</strong>&nbsp;of a given movie from a given shop.</li><li><strong>Drop</strong>: Drops off a&nbsp;<strong>previously rented copy</strong>&nbsp;of a given movie at a given shop.</li><li><strong>Report</strong>: Returns the&nbsp;<strong>cheapest 5 rented movies</strong>&nbsp;(possibly of the same movie ID) as a 2D list&nbsp;<code>res</code>&nbsp;where&nbsp;<code>res[j] = [shop<sub>j</sub>, movie<sub>j</sub>]</code>&nbsp;describes that the&nbsp;<code>j<sup>th</sup></code>&nbsp;cheapest rented movie&nbsp;<code>movie<sub>j</sub></code>&nbsp;was rented from the shop&nbsp;<code>shop<sub>j</sub></code>. The movies in&nbsp;<code>res</code>&nbsp;should be sorted by&nbsp;<strong>price&nbsp;</strong>in ascending order, and in case of a tie, the one with the&nbsp;<strong>smaller&nbsp;</strong><code>shop<sub>j</sub></code>&nbsp;should appear first, and if there is still tie, the one with the&nbsp;<strong>smaller&nbsp;</strong><code>movie<sub>j</sub></code>&nbsp;should appear first. If there are fewer than 5 rented movies, then all of them should be returned. If no movies are currently being rented, then an empty list should be returned.</li></ul>



<p>Implement the&nbsp;<code>MovieRentingSystem</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>MovieRentingSystem(int n, int[][] entries)</code>&nbsp;Initializes the&nbsp;<code>MovieRentingSystem</code>&nbsp;object with&nbsp;<code>n</code>&nbsp;shops and the movies in&nbsp;<code>entries</code>.</li><li><code>List&lt;Integer&gt; search(int movie)</code>&nbsp;Returns a list of shops that have an&nbsp;<strong>unrented copy</strong>&nbsp;of the given&nbsp;<code>movie</code>&nbsp;as described above.</li><li><code>void rent(int shop, int movie)</code>&nbsp;Rents the given&nbsp;<code>movie</code>&nbsp;from the given&nbsp;<code>shop</code>.</li><li><code>void drop(int shop, int movie)</code>&nbsp;Drops off a previously rented&nbsp;<code>movie</code>&nbsp;at the given&nbsp;<code>shop</code>.</li><li><code>List&lt;List&lt;Integer&gt;&gt; report()</code>&nbsp;Returns a list of cheapest&nbsp;<strong>rented</strong>&nbsp;movies as described above.</li></ul>



<p><strong>Note:</strong>&nbsp;The test cases will be generated such that&nbsp;<code>rent</code>&nbsp;will only be called if the shop has an&nbsp;<strong>unrented</strong>&nbsp;copy of the movie, and&nbsp;<code>drop</code>&nbsp;will only be called if the shop had&nbsp;<strong>previously rented</strong>&nbsp;out the movie.</p>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input</strong>
["MovieRentingSystem", "search", "rent", "rent", "report", "drop", "search"]
[[3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]], [1], [0, 1], [1, 2], [], [1, 2], [2]]
<strong>Output</strong>
[null, [1, 0, 2], null, null, [[0, 1], [1, 2]], null, [0, 1]]

<strong>Explanation</strong>
MovieRentingSystem movieRentingSystem = new MovieRentingSystem(3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]);
movieRentingSystem.search(1);  // return [1, 0, 2], Movies of ID 1 are unrented at shops 1, 0, and 2. Shop 1 is cheapest; shop 0 and 2 are the same price, so order by shop number.
movieRentingSystem.rent(0, 1); // Rent movie 1 from shop 0. Unrented movies at shop 0 are now [2,3].
movieRentingSystem.rent(1, 2); // Rent movie 2 from shop 1. Unrented movies at shop 1 are now [1].
movieRentingSystem.report();   // return [[0, 1], [1, 2]]. Movie 1 from shop 0 is cheapest, followed by movie 2 from shop 1.
movieRentingSystem.drop(1, 2); // Drop off movie 2 at shop 1. Unrented movies at shop 1 are now [1,2].
movieRentingSystem.search(2);  // return [0, 1]. Movies of ID 2 are unrented at shops 0 and 1. Shop 0 is cheapest, followed by shop 1.
</pre>



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



<ul class="wp-block-list"><li><code>1 &lt;= n &lt;= 3 * 10<sup>5</sup></code></li><li><code>1 &lt;= entries.length &lt;= 10<sup>5</sup></code></li><li><code>0 &lt;= shop<sub>i</sub>&nbsp;&lt; n</code></li><li><code>1 &lt;= movie<sub>i</sub>, price<sub>i</sub>&nbsp;&lt;= 10<sup>4</sup></code></li><li>Each shop carries&nbsp;<strong>at most one</strong>&nbsp;copy of a movie&nbsp;<code>movie<sub>i</sub></code>.</li><li>At most&nbsp;<code>10<sup>5</sup></code>&nbsp;calls&nbsp;<strong>in total</strong>&nbsp;will be made to&nbsp;<code>search</code>,&nbsp;<code>rent</code>,&nbsp;<code>drop</code>&nbsp;and&nbsp;<code>report</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: Hashtable + TreeSet</strong></h2>



<p>We need three containers:<br>1. <strong><em>movies</em></strong> tracks the {movie -&gt; price} of each shop. This is readonly to get the price of a movie for generating keys for treesets.<br>2. <strong><em>unrented</em></strong> tracks unrented movies keyed by movie id,  value is a treeset ordered by {price, shop}.<br>3. <strong><em>rented</em></strong> tracks rented movies, a treeset <meta charset="utf-8">ordered by {price, shop, movie}</p>



<p>Note: By using array&lt;int, 3&gt; we can unpack values like below:<br>array&lt;int, 3&gt; entries; // {price, shop, movie}<br>for (const auto [price, shop, moive] : entries)<br>  &#8230;</p>



<p>Time complexity: <br>Init: O(nlogn)<br>rent / drop: O(logn)<br>search / report: O(1)</p>



<p>Space complexity: O(n)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class MovieRentingSystem {
public:
  MovieRentingSystem(int n, vector&lt;vector&lt;int&gt;&gt;&amp; entries): movies(n) {
    for (const auto&amp; e : entries) {
      const int shop = e[0];
      const int movie = e[1];
      const int price = e[2];
      movies[shop].emplace(movie, price);
      unrented[movie].emplace(price, shop);
    }
  }

  vector&lt;int&gt; search(int movie) {
    vector&lt;int&gt; shops;
    for (const auto [price, shop] : unrented[movie]) {
      shops.push_back(shop);
      if (shops.size() == 5) break;
    }
    return shops;
  }

  void rent(int shop, int movie) {
    const int price = movies[shop][movie];
    unrented[movie].erase({price, shop});
    rented.insert({price, shop, movie});
  }

  void drop(int shop, int movie) {
    const int price = movies[shop][movie];
    rented.erase({price, shop, movie});
    unrented[movie].emplace(price, shop);
  }

  vector&lt;vector&lt;int&gt;&gt; report() {
    vector&lt;vector&lt;int&gt;&gt; ans;
    for (const auto&amp; [price, shop, movie] : rented) {
      ans.push_back({shop, movie});
      if (ans.size() == 5) break;
    }
    return ans;
  }
private:
  vector&lt;unordered_map&lt;int, int&gt;&gt; movies; // shop -&gt; {movie -&gt; price}
  unordered_map&lt;int, set&lt;pair&lt;int, int&gt;&gt;&gt; unrented; // movie -&gt; {price, shop}
  set&lt;array&lt;int, 3&gt;&gt; rented; // {price, shop, movie}
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-1912-design-movie-rental-system/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2102. Sequentially Ordinal Rank Tracker</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-2102-sequentially-ordinal-rank-tracker/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-2102-sequentially-ordinal-rank-tracker/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 12 Dec 2021 22:07:45 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[iterator]]></category>
		<category><![CDATA[set]]></category>
		<category><![CDATA[treeset]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9143</guid>

					<description><![CDATA[A scenic location is represented by its&#160;name&#160;and attractiveness&#160;score, where&#160;name&#160;is a&#160;unique&#160;string among all locations and&#160;score&#160;is an integer. Locations can be ranked from the best to the&#8230;]]></description>
										<content:encoded><![CDATA[
<p>A scenic location is represented by its&nbsp;<code>name</code>&nbsp;and attractiveness&nbsp;<code>score</code>, where&nbsp;<code>name</code>&nbsp;is a&nbsp;<strong>unique</strong>&nbsp;string among all locations and&nbsp;<code>score</code>&nbsp;is an integer. Locations can be ranked from the best to the worst. The&nbsp;<strong>higher</strong>&nbsp;the score, the better the location. If the scores of two locations are equal, then the location with the&nbsp;<strong>lexicographically smaller</strong>&nbsp;name is better.</p>



<p>You are building a system that tracks the ranking of locations with the system initially starting with no locations. It supports:</p>



<ul class="wp-block-list"><li><strong>Adding</strong>&nbsp;scenic locations,&nbsp;<strong>one at a time</strong>.</li><li><strong>Querying</strong>&nbsp;the&nbsp;<code>i<sup>th</sup></code>&nbsp;<strong>best</strong>&nbsp;location of&nbsp;<strong>all locations already added</strong>, where&nbsp;<code>i</code>&nbsp;is the number of times the system has been queried (including the current query).<ul><li>For example, when the system is queried for the&nbsp;<code>4<sup>th</sup></code>&nbsp;time, it returns the&nbsp;<code>4<sup>th</sup></code>&nbsp;best location of all locations already added.</li></ul></li></ul>



<p>Note that the test data are generated so that&nbsp;<strong>at any time</strong>, the number of queries&nbsp;<strong>does not exceed</strong>&nbsp;the number of locations added to the system.</p>



<p>Implement the&nbsp;<code>SORTracker</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>SORTracker()</code>&nbsp;Initializes the tracker system.</li><li><code>void add(string name, int score)</code>&nbsp;Adds a scenic location with&nbsp;<code>name</code>&nbsp;and&nbsp;<code>score</code>&nbsp;to the system.</li><li><code>string get()</code>&nbsp;Queries and returns the&nbsp;<code>i<sup>th</sup></code>&nbsp;best location, where&nbsp;<code>i</code>&nbsp;is the number of times this method has been invoked (including this invocation).</li></ul>



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



<pre class="urvanov-syntax-highlighter-plain-tag">&lt;strong&gt;Input&lt;/strong&gt;
[&quot;SORTracker&quot;, &quot;add&quot;, &quot;add&quot;, &quot;get&quot;, &quot;add&quot;, &quot;get&quot;, &quot;add&quot;, &quot;get&quot;, &quot;add&quot;, &quot;get&quot;, &quot;add&quot;, &quot;get&quot;, &quot;get&quot;]
[[], [&quot;bradford&quot;, 2], [&quot;branford&quot;, 3], [], [&quot;alps&quot;, 2], [], [&quot;orland&quot;, 2], [], [&quot;orlando&quot;, 3], [], [&quot;alpine&quot;, 2], [], []]
&lt;strong&gt;Output&lt;/strong&gt;
[null, null, null, &quot;branford&quot;, null, &quot;alps&quot;, null, &quot;bradford&quot;, null, &quot;bradford&quot;, null, &quot;bradford&quot;, &quot;orland&quot;]
&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt; 
SORTracker tracker = new SORTracker(); // Initialize the tracker system.
tracker.add(&quot;bradford&quot;, 2);            // Add location with name=&quot;bradford&quot; and score=2 to the system.
tracker.add(&quot;branford&quot;, 3);            // Add location with name=&quot;branford&quot; and score=3 to the system.
tracker.get();                         // The sorted locations, from best to worst, are: branford, bradford. 
                                       // Note that branford precedes bradford due to its &lt;strong&gt;higher score&lt;/strong&gt; (3 &amp;gt; 2). 
                                       // This is the 1&lt;sup&gt;st&lt;/sup&gt; time get() is called, so return the best location: &quot;branford&quot;. 
tracker.add(&quot;alps&quot;, 2);                // Add location with name=&quot;alps&quot; and score=2 to the system.
tracker.get();                         // Sorted locations: branford, alps, bradford. 
                                       // Note that alps precedes bradford even though they have the same score (2). 
                                       // This is because &quot;alps&quot; is &lt;strong&gt;lexicographically smaller&lt;/strong&gt; than &quot;bradford&quot;. 
                                       // Return the 2&lt;sup&gt;nd&lt;/sup&gt; best location &quot;alps&quot;, as it is the 2&lt;sup&gt;nd&lt;/sup&gt; time get() is called.
tracker.add(&quot;orland&quot;, 2);              // Add location with name=&quot;orland&quot; and score=2 to the system.
tracker.get();                         // Sorted locations: branford, alps, bradford, orland. 
                                       // Return &quot;bradford&quot;, as it is the 3&lt;sup&gt;rd&lt;/sup&gt; time get() is called. 
tracker.add(&quot;orlando&quot;, 3);             // Add location with name=&quot;orlando&quot; and score=3 to the system.
tracker.get();                         // Sorted locations: branford, orlando, alps, bradford, orland. 
                                       // Return &quot;bradford&quot;. 
tracker.add(&quot;alpine&quot;, 2);              // Add location with name=&quot;alpine&quot; and score=2 to the system.
tracker.get();                         // Sorted locations: branford, orlando, alpine, alps, bradford, orland. 
                                       // Return &quot;bradford&quot;. 
tracker.get();                         // Sorted locations: branford, orlando, alpine, alps, bradford, orland. 
                                       // Return &quot;orland&quot;.
&lt;/p&gt;</pre>



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



<ul class="wp-block-list"><li><code>name</code>&nbsp;consists of lowercase English letters, and is unique among all locations.</li><li><code>1 &lt;= name.length &lt;= 10</code></li><li><code>1 &lt;= score &lt;= 10<sup>5</sup></code></li><li>At any time, the number of calls to&nbsp;<code>get</code>&nbsp;does not exceed the number of calls to&nbsp;<code>add</code>.</li><li>At most&nbsp;<code>4 * 10<sup>4</sup></code>&nbsp;calls&nbsp;<strong>in total</strong>&nbsp;will be made to&nbsp;<code>add</code>&nbsp;and&nbsp;<code>get</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: TreeSet w/ Iterator</strong></h2>



<p>Use a treeset to store all the entries and use a iterator that points to the entry to return. When inserting a new entry into the tree, if it&#8217;s higher than the current element then let the iterator go backward one step. </p>



<p>Time complexity:  add O(logn) / get O(1)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class SORTracker {
public:
  SORTracker() {}

  void add(string name, int score) {    
    if (*s.emplace(-score, name).first &lt; *cit) --cit;
  }

  string get() {
    return (cit++)-&gt;second;
  }
private:
  set&lt;pair&lt;int, string&gt;&gt; s;
  // Note: cit points to begin(s) after first insertion.
  set&lt;pair&lt;int, string&gt;&gt;::const_iterator cit = end(s);
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-2102-sequentially-ordinal-rank-tracker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 211. Design Add and Search Words Data Structure</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-211-design-add-and-search-words-data-structure/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-211-design-add-and-search-words-data-structure/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 06 Dec 2021 03:55:03 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[hashtable]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[string]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9050</guid>

					<description><![CDATA[Design a data structure that supports adding new words and finding if a string matches any previously added string. Implement the&#160;WordDictionary&#160;class: WordDictionary()&#160;Initializes the object. void&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Design a data structure that supports adding new words and finding if a string matches any previously added string.</p>



<p>Implement the&nbsp;<code>WordDictionary</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>WordDictionary()</code>&nbsp;Initializes the object.</li><li><code>void addWord(word)</code>&nbsp;Adds&nbsp;<code>word</code>&nbsp;to the data structure, it can be matched later.</li><li><code>bool search(word)</code>&nbsp;Returns&nbsp;<code>true</code>&nbsp;if there is any string in the data structure that matches&nbsp;<code>word</code>&nbsp;or&nbsp;<code>false</code>&nbsp;otherwise.&nbsp;<code>word</code>&nbsp;may contain dots&nbsp;<code>'.'</code>&nbsp;where dots can be matched with any letter.</li></ul>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input</strong>
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
<strong>Output</strong>
[null,null,null,null,false,true,true,true]
<strong>Explanation</strong> 
WordDictionary wordDictionary = new WordDictionary(); 
wordDictionary.addWord("bad"); 
wordDictionary.addWord("dad"); 
wordDictionary.addWord("mad"); 
wordDictionary.search("pad"); // return False 
wordDictionary.search("bad"); // return True 
wordDictionary.search(".ad"); // return True 
wordDictionary.search("b.."); // return True
</pre>



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



<ul class="wp-block-list"><li><code>1 &lt;= word.length &lt;= 500</code></li><li><code>word</code>&nbsp;in&nbsp;<code>addWord</code>&nbsp;consists lower-case English letters.</li><li><code>word</code>&nbsp;in&nbsp;<code>search</code>&nbsp;consist of&nbsp;&nbsp;<code>'.'</code>&nbsp;or lower-case English letters.</li><li>At most&nbsp;<code>50000</code>&nbsp;calls will be made to&nbsp;<code>addWord</code>&nbsp;and&nbsp;<code>search</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: Hashtables</strong></h2>



<p>The first hashtable stores all the words, if there is no dot in the search pattern. Do a full match.</p>



<p>There are also per length hashtable to store words of length k. And do a brute force match.</p>



<p>Time complexity: Init: O(n*l)<br>search: best: O(l) worst: O(n*l)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class WordDictionary {
public:
  // Adds a word into the data structure.
  void addWord(string word) {
    words.insert(word);
    ws[word.length()].insert(word);
  }

  // Returns if the word is in the data structure. A word could
  // contain the dot character '.' to represent any one letter.
  bool search(string word) {
    if (word.find(&quot;.&quot;) == string::npos)
      return words.count(word);
    
    for (const string&amp; w : ws[word.length()])
      if (match(word, w)) return true;    

    return false;
  }
    
  bool match(const string&amp; p, const string&amp; w) {
    for (int i = 0; i &lt; p.length(); ++i) {
      if (p[i] == '.') continue;
      if (p[i] != w[i]) return false;
    }
    return true;
  }
private:
    unordered_set&lt;string&gt; words;
    unordered_map&lt;int, unordered_set&lt;string&gt;&gt; ws;
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-211-design-add-and-search-words-data-structure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1845. Seat Reservation Manager</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-1845-seat-reservation-manager/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-1845-seat-reservation-manager/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 01 May 2021 22:28:54 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[treeset]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=8409</guid>

					<description><![CDATA[Design a system that manages the reservation state of&#160;n&#160;seats that are numbered from&#160;1&#160;to&#160;n. Implement the&#160;SeatManager&#160;class: SeatManager(int n)&#160;Initializes a&#160;SeatManager&#160;object that will manage&#160;n&#160;seats numbered from&#160;1&#160;to&#160;n. All seats&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Design a system that manages the reservation state of&nbsp;<code>n</code>&nbsp;seats that are numbered from&nbsp;<code>1</code>&nbsp;to&nbsp;<code>n</code>.</p>



<p>Implement the&nbsp;<code>SeatManager</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>SeatManager(int n)</code>&nbsp;Initializes a&nbsp;<code>SeatManager</code>&nbsp;object that will manage&nbsp;<code>n</code>&nbsp;seats numbered from&nbsp;<code>1</code>&nbsp;to&nbsp;<code>n</code>. All seats are initially available.</li><li><code>int reserve()</code>&nbsp;Fetches the&nbsp;<strong>smallest-numbered</strong>&nbsp;unreserved seat, reserves it, and returns its number.</li><li><code>void unreserve(int seatNumber)</code>&nbsp;Unreserves the seat with the given&nbsp;<code>seatNumber</code>.</li></ul>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input</strong>
["SeatManager", "reserve", "reserve", "unreserve", "reserve", "reserve", "reserve", "reserve", "unreserve"]
[[5], [], [], [2], [], [], [], [], [5]]
<strong>Output</strong>

[null, 1, 2, null, 2, 3, 4, 5, null]

<strong>Explanation</strong> SeatManager seatManager = new SeatManager(5); // Initializes a SeatManager with 5 seats. seatManager.reserve(); // All seats are available, so return the lowest numbered seat, which is 1. seatManager.reserve(); // The available seats are [2,3,4,5], so return the lowest of them, which is 2. seatManager.unreserve(2); // Unreserve seat 2, so now the available seats are [2,3,4,5]. seatManager.reserve(); // The available seats are [2,3,4,5], so return the lowest of them, which is 2. seatManager.reserve(); // The available seats are [3,4,5], so return the lowest of them, which is 3. seatManager.reserve(); // The available seats are [4,5], so return the lowest of them, which is 4. seatManager.reserve(); // The only available seat is seat 5, so return 5. seatManager.unreserve(5); // Unreserve seat 5, so now the available seats are [5].
</pre>



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



<ul class="wp-block-list"><li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= seatNumber &lt;= n</code></li><li>For each call to&nbsp;<code>reserve</code>, it is guaranteed that there will be at least one unreserved seat.</li><li>For each call to&nbsp;<code>unreserve</code>, it is guaranteed that&nbsp;<code>seatNumber</code>&nbsp;will be reserved.</li><li>At most&nbsp;<code>10<sup>5</sup></code>&nbsp;calls&nbsp;<strong>in total</strong>&nbsp;will be made to&nbsp;<code>reserve</code>&nbsp;and&nbsp;<code>unreserve</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: TreeSet</strong></h2>



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



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class SeatManager {
public:
  SeatManager(int n) {
    for (int i = 1; i &lt;= n; ++i)
      s_.insert(i);
  }

  int reserve() {    
    int seat = *begin(s_);
    s_.erase(begin(s_));    
    return seat;
  }

  void unreserve(int seatNumber) {
    s_.insert(seatNumber);    
  }
private:
  set&lt;int&gt; s_;
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-1845-seat-reservation-manager/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1825. Finding MK Average</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-1825-finding-mk-average/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-1825-finding-mk-average/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Wed, 14 Apr 2021 02:58:09 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[multiset]]></category>
		<category><![CDATA[ordered set]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=8350</guid>

					<description><![CDATA[You are given two integers,&#160;m&#160;and&#160;k, and a stream of integers. You are tasked to implement a data structure that calculates the&#160;MKAverage&#160;for the stream. The&#160;MKAverage&#160;can be&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given two integers,&nbsp;<code>m</code>&nbsp;and&nbsp;<code>k</code>, and a stream of integers. You are tasked to implement a data structure that calculates the&nbsp;<strong>MKAverage</strong>&nbsp;for the stream.</p>



<p>The&nbsp;<strong>MKAverage</strong>&nbsp;can be calculated using these steps:</p>



<ol class="wp-block-list"><li>If the number of the elements in the stream is less than&nbsp;<code>m</code>&nbsp;you should consider the&nbsp;<strong>MKAverage</strong>&nbsp;to be&nbsp;<code>-1</code>. Otherwise, copy the last&nbsp;<code>m</code>&nbsp;elements of the stream to a separate container.</li><li>Remove the smallest&nbsp;<code>k</code>&nbsp;elements and the largest&nbsp;<code>k</code>&nbsp;elements from the container.</li><li>Calculate the average value for the rest of the elements&nbsp;<strong>rounded down to the nearest integer</strong>.</li></ol>



<p>Implement the&nbsp;<code>MKAverage</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>MKAverage(int m, int k)</code>&nbsp;Initializes the&nbsp;<strong>MKAverage</strong>&nbsp;object with an empty stream and the two integers&nbsp;<code>m</code>&nbsp;and&nbsp;<code>k</code>.</li><li><code>void addElement(int num)</code>&nbsp;Inserts a new element&nbsp;<code>num</code>&nbsp;into the stream.</li><li><code>int calculateMKAverage()</code>&nbsp;Calculates and returns the&nbsp;<strong>MKAverage</strong>&nbsp;for the current stream&nbsp;<strong>rounded down to the nearest integer</strong>.</li></ul>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input</strong>
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
<strong>Output</strong>
[null, null, null, -1, null, 3, null, null, null, 5]
<p><strong>Explanation</strong> MKAverage obj = new MKAverage(3, 1); obj.addElement(3); // current elements are [3] obj.addElement(1); // current elements are [3,1] obj.calculateMKAverage(); // return -1, because m = 3 and only 2 elements exist. obj.addElement(10); // current elements are [3,1,10] obj.calculateMKAverage(); // The last 3 elements are [3,1,10]. // After removing smallest and largest 1 element the container will be <code>[3]. // The average of [3] equals 3/1 = 3, return 3 obj.addElement(5); // current elements are [3,1,10,5] obj.addElement(5); // current elements are [3,1,10,5,5] obj.addElement(5); // current elements are [3,1,10,5,5,5] obj.calculateMKAverage(); // The last 3 elements are [5,5,5]. // After removing smallest and largest 1 element the container will be <code>[5]. // The average of [5] equals 5/1 = 5, return 5</code></code></p>
</pre>



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



<ul class="wp-block-list"><li><code>3 &lt;= m &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= k*2 &lt; m</code></li><li><code>1 &lt;= num &lt;= 10<sup>5</sup></code></li><li>At most&nbsp;<code>10<sup>5</sup></code>&nbsp;calls will be made to&nbsp;<code>addElement</code>&nbsp;and&nbsp;<code>calculateMKAverage</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution 1: Multiset * 3</strong></h2>



<p>Use three multiset to track the left part (smallest k elements), right part (largest k elements) and mid (middle part of m &#8211; 2*k elements).</p>



<p>Time complexity: addElememt: O(logn), average: O(1)<br>Space complexity: O(n)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">class MKAverage {
public:
  MKAverage(int m, int k): 
    sum(0), m(m), k(k), n(m - 2*k) {}

  void addElement(int num) {
    if (q.size() == m) {      
      remove(q.front());
      q.pop();
    }
    q.push(num);
    add(num);
  }

  int calculateMKAverage() {    
    return (q.size() &lt; m) ? -1 : sum / n;
  }
private:
  void add(int x) {
    left.insert(x);
    
    if (left.size() &gt; k) {
      auto it = prev(end(left));
      sum += *it;
      mid.insert(*it);      
      left.erase(it);
    }
    
    if (mid.size() &gt; n) {
      auto it = prev(end(mid));
      sum -= *it; 
      right.insert(*it);
      mid.erase(it);
    }
  }
  
  void remove(int x) {
    if (x &lt;= *rbegin(left)) {
      left.erase(left.find(x));
    } else if (x &lt;= *rbegin(mid)) {
      sum -= x;
      mid.erase(mid.find(x));
    } else {
      right.erase(right.find(x));
    }
    
    if (left.size() &lt; k) {
      auto it = begin(mid);
      sum -= *it;
      left.insert(*it);
      mid.erase(it);
    }
    
    if (mid.size() &lt; n) {
      auto it = begin(right);
      sum += *it;
      mid.insert(*it);
      right.erase(it);
    }
  }
  
  queue&lt;int&gt; q;
  multiset&lt;int&gt; left, mid, right;  
  long sum;
  const int m;
  const int k;
  const int n;
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-1825-finding-mk-average/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1656. Design an Ordered Stream</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-1656-design-an-ordered-stream/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-1656-design-an-ordered-stream/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 15 Nov 2020 04:16:02 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[easy]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7666</guid>

					<description><![CDATA[There are&#160;n&#160;(id, value)&#160;pairs, where&#160;id&#160;is an integer between&#160;1&#160;and&#160;n&#160;and&#160;value&#160;is a string. No two pairs have the same&#160;id. Design a stream that takes the&#160;n&#160;pairs in an&#160;arbitrary&#160;order, and returns&#8230;]]></description>
										<content:encoded><![CDATA[
<p>There are&nbsp;<code>n</code>&nbsp;<code>(id, value)</code>&nbsp;pairs, where&nbsp;<code>id</code>&nbsp;is an integer between&nbsp;<code>1</code>&nbsp;and&nbsp;<code>n</code>&nbsp;and&nbsp;<code>value</code>&nbsp;is a string. No two pairs have the same&nbsp;<code>id</code>.</p>



<p>Design a stream that takes the&nbsp;<code>n</code>&nbsp;pairs in an&nbsp;<strong>arbitrary</strong>&nbsp;order, and returns the values over several calls in&nbsp;<strong>increasing order of their ids</strong>.</p>



<p>Implement the&nbsp;<code>OrderedStream</code>&nbsp;class:</p>



<ul class="wp-block-list"><li><code>OrderedStream(int n)</code>&nbsp;Constructs the stream to take&nbsp;<code>n</code>&nbsp;values and sets a current&nbsp;<code>ptr</code>&nbsp;to&nbsp;<code>1</code>.</li><li><code>String[] insert(int id, String value)</code>&nbsp;Stores the new&nbsp;<code>(id, value)</code>&nbsp;pair in the stream. After storing the pair:<ul><li>If the stream has stored a pair with&nbsp;<code>id = ptr</code>, then find the&nbsp;<strong>longest contiguous incrementing sequence</strong>&nbsp;of ids starting with&nbsp;<code>id = ptr</code>&nbsp;and return a list of the values associated with those ids&nbsp;<strong>in order</strong>. Then, update&nbsp;<code>ptr</code>&nbsp;to the last&nbsp;<code>id + 1</code>.</li><li>Otherwise, return an empty list.</li></ul></li></ul>



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



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2020/11/10/q1.gif" alt=""/></figure>



<pre class="wp-block-preformatted wp-block-preformatted;crayon:false"><strong>Input</strong>
["OrderedStream", "insert", "insert", "insert", "insert", "insert"]
[[5], [3, "ccccc"], [1, "aaaaa"], [2, "bbbbb"], [5, "eeeee"], [4, "ddddd"]]
<strong>Output</strong>
[null, [], ["aaaaa"], ["bbbbb", "ccccc"], [], ["ddddd", "eeeee"]]
<strong>Explanation</strong>
OrderedStream os= new OrderedStream(5);
os.insert(3, "ccccc"); // Inserts (3, "ccccc"), returns [].
os.insert(1, "aaaaa"); // Inserts (1, "aaaaa"), returns ["aaaaa"].
os.insert(2, "bbbbb"); // Inserts (2, "bbbbb"), returns ["bbbbb", "ccccc"].
os.insert(5, "eeeee"); // Inserts (5, "eeeee"), returns [].
os.insert(4, "ddddd"); // Inserts (4, "ddddd"), returns ["ddddd", "eeeee"].
</pre>



<h2 class="wp-block-heading"><strong>Solution: Straight Forward</strong></h2>



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



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class OrderedStream {
public:
  OrderedStream(int n): data_(n + 1) {}

  vector&lt;string&gt; insert(int id, string value) {
    data_[id] = value;
    vector&lt;string&gt; ans;
    if (ptr_ == id)
      while (ptr_ &lt; data_.size() &amp;&amp; !data_[ptr_].empty())
        ans.push_back(data_[ptr_++]);
    return ans;
  }
private:
  int ptr_ = 1;
  vector&lt;string&gt; data_;
};</pre>

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

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class OrderedStream:
  def __init__(self, n: int):
    self.data = [None] * (n + 1)
    self.ptr = 1

  def insert(self, id: int, value: str) -&gt; List[str]:
    self.data[id] = value
    if id == self.ptr:
      while self.ptr &lt; len(self.data) and self.data[self.ptr]:
        self.ptr += 1
      return self.data[id:self.ptr]
    return []</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-1656-design-an-ordered-stream/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1146. Snapshot Array</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-1146-snapshot-array/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-1146-snapshot-array/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 04 Aug 2019 17:52:50 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[map]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=5388</guid>

					<description><![CDATA[Implement a SnapshotArray that supports the following interface: SnapshotArray(int length)&#160;initializes an array-like data structure with the given length.&#160;&#160;Initially, each element equals 0. void set(index, val)&#160;sets&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Implement a SnapshotArray that supports the following interface:</p>



<ul class="wp-block-list"><li><code>SnapshotArray(int length)</code>&nbsp;initializes an array-like data structure with the given length.&nbsp;&nbsp;<strong>Initially, each element equals 0</strong>.</li><li><code>void set(index, val)</code>&nbsp;sets the element at the given&nbsp;<code>index</code>&nbsp;to be equal to&nbsp;<code>val</code>.</li><li><code>int snap()</code>&nbsp;takes a snapshot of the array and returns the&nbsp;<code>snap_id</code>: the total number of times we called&nbsp;<code>snap()</code>&nbsp;minus&nbsp;<code>1</code>.</li><li><code>int get(index, snap_id)</code>&nbsp;returns the value at the given&nbsp;<code>index</code>, at the time we took the snapshot with the given&nbsp;<code>snap_id</code></li></ul>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> ["SnapshotArray","set","snap","set","get"]
[[3],[0,5],[],[0,6],[0,0]]
<strong>Output:</strong> [null,null,0,null,5]
<strong>Explanation: </strong>
SnapshotArray snapshotArr = new SnapshotArray(3); // set the length to be 3
snapshotArr.set(0,5);  // Set array[0] = 5
snapshotArr.snap();  // Take a snapshot, return snap_id = 0
snapshotArr.set(0,6);
snapshotArr.get(0,0);  // Get the value of array[0] with snap_id = 0, return 5</pre>



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



<ul class="wp-block-list"><li><code>1 &lt;= length&nbsp;&lt;= 50000</code></li><li>At most&nbsp;<code>50000</code>&nbsp;calls will be made to&nbsp;<code>set</code>,&nbsp;<code>snap</code>, and&nbsp;<code>get</code>.</li><li><code>0 &lt;= index&nbsp;&lt;&nbsp;length</code></li><li><code>0 &lt;=&nbsp;snap_id &lt;&nbsp;</code>(the total number of times we call&nbsp;<code>snap()</code>)</li><li><code>0 &lt;=&nbsp;val &lt;= 10^9</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: map + upper_bound</strong></h2>



<p>Use a vector to store maps, one map per element.<br>The map stores {snap_id -> val}, use upper_bound to find the first version > snap_id and use previous version&#8217;s value.</p>



<p>Time complexity: <br>Set: O(log|snap_id|)<br>Get: O(log|snap_id|)  <br>Snap: O(1)<br>Space complexity: O(length + set_calls)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class SnapshotArray {
public:
  SnapshotArray(int length): id_(0), vals_(length) {}

  void set(int index, int val) {
    vals_[index][id_] = val;
  }

  int snap() { return id_++; }

  int get(int index, int snap_id) const {
    auto it = vals_[index].upper_bound(snap_id);
    if (it == begin(vals_[index])) return 0;
    return prev(it)-&gt;second;
  }
private:
  int id_;
  vector&lt;map&lt;int, int&gt;&gt; vals_;
};</pre>
</div></div>



<p><br></p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-1146-snapshot-array/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 641. Design Circular Deque</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-641-design-circular-deque/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-641-design-circular-deque/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 15 Jul 2018 03:58:04 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[circular]]></category>
		<category><![CDATA[deque]]></category>
		<category><![CDATA[desgin]]></category>
		<category><![CDATA[easy]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=3147</guid>

					<description><![CDATA[Problem Design your implementation of the circular double-ended queue (deque). Your implementation should support following operations: MyCircularDeque(k): Constructor, set the size of the deque to&#8230;]]></description>
										<content:encoded><![CDATA[<h1><strong>Problem</strong></h1>
<p>Design your implementation of the circular double-ended queue (deque).<br />
Your implementation should support following operations:</p>
<ul>
<li>MyCircularDeque(k): Constructor, set the size of the deque to be k.</li>
<li>insertFront(): Adds an item at the front of Deque. Return true if the operation is successful.</li>
<li>insertLast(): Adds an item at the rear of Deque. Return true if the operation is successful.</li>
<li>deleteFront(): Deletes an item from the front of Deque. Return true if the operation is successful.</li>
<li>deleteLast(): Deletes an item from the rear of Deque. Return true if the operation is successful.</li>
<li>getFront(): Gets the front item from the Deque. If the deque is empty, return -1.</li>
<li>getRear(): Gets the last item from Deque. If the deque is empty, return -1.</li>
<li>isEmpty(): Checks whether Deque is empty or not.</li>
<li>isFull(): Checks whether Deque is full or not.</li>
</ul>
<p><strong>Example:</strong></p>
<pre class="crayon:false ">MyCircularDeque circularDeque = new MycircularDeque(3); // set the size to be 3
circularDeque.insertLast(1);			// return true
circularDeque.insertLast(2);			// return true
circularDeque.insertFront(3);			// return true
circularDeque.insertFront(4);			// return false, the queue is full
circularDeque.getRear();  				// return 32
circularDeque.isFull();				// return true
circularDeque.deleteLast();			// return true
circularDeque.insertFront(4);			// return true
circularDeque.getFront();				// return 4
</pre>
<p><strong>Note:</strong></p>
<ul>
<li>All values will be in the range of [1, 1000].</li>
<li>The number of operations will be in the range of [1, 1000].</li>
<li>Please do not use the built-in Deque library.</li>
</ul>
<h1><strong>Solution</strong></h1>
<p>Using head and tail to pointer to the head and the tail in the circular buffer.</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 20 ms
class MyCircularDeque {
public:
  /** Initialize your data structure here. Set the size of the deque to be k. */
  MyCircularDeque(int k): k_(k), q_(k), head_(1), tail_(-1), size_(0) {}

  /** Adds an item at the front of Deque. Return true if the operation is successful. */
  bool insertFront(int value) {
    if (isFull()) return false;
    head_ = (head_ - 1 + k_) % k_;
    q_[head_] = value;
    if (size_ == 0) tail_ = head_;
    ++size_;
    return true;
  }

  /** Adds an item at the rear of Deque. Return true if the operation is successful. */
  bool insertLast(int value) {
    if (isFull()) return false;
    tail_ = (tail_ + 1 + k_) % k_;
    q_[tail_] = value;
    if (size_ == 0) head_ = tail_;
    ++size_;
    return true;  
  }

  /** Deletes an item from the front of Deque. Return true if the operation is successful. */
  bool deleteFront() {
    if (isEmpty()) return false;
    head_ = (head_ + 1 + k_) % k_;
    --size_;
    return true;
  }

  /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
  bool deleteLast() {
    if (isEmpty()) return false;
    tail_ = (tail_ - 1 + k_) % k_;
    --size_;
    return true;
  }

  /** Get the front item from the deque. */
  int getFront() {
    if (isEmpty()) return -1;
    return q_[head_];
  }

  /** Get the last item from the deque. */
  int getRear() {
    if (isEmpty()) return -1;
    return q_[tail_];
  }

  /** Checks whether the circular deque is empty or not. */
  bool isEmpty() {
    return size_ == 0;
  }

  /** Checks whether the circular deque is full or not. */
  bool isFull() {
    return size_ == k_;
  }
private:
  const int k_;
  int head_;
  int tail_;
  int size_;
  vector&lt;int&gt; q_;
};</pre><p></p>
<h1><strong>Related Problems</strong></h1>
<ul>
<li><a href="http://zxi.mytechroad.com/blog/uncategorized/leetcode-622-design-circular-queue/">花花酱 LeetCode 622. Design Circular Queue</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-641-design-circular-deque/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 432. All O`one Data Structure</title>
		<link>https://zxi.mytechroad.com/blog/list/leetcode-432-all-oone-data-structure/</link>
					<comments>https://zxi.mytechroad.com/blog/list/leetcode-432-all-oone-data-structure/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 07 Apr 2018 04:44:37 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[Hashtable]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[O(1)]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=2434</guid>

					<description><![CDATA[Problem 题目大意：设计一种数据结构，支持inc/dec/getmaxkey/getminkey操作，必须都在O(1)时间内完成。 https://leetcode.com/problems/all-oone-data-structure/description/ Implement a data structure supporting the following operations: Inc(Key) &#8211; Inserts a new key with value 1. Or increments an existing key by&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe title="花花酱 LeetCode 432. All O`one Data Structure - 刷题找工作 EP178" width="500" height="375" src="https://www.youtube.com/embed/wYqLisoH80w?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h1>Problem</h1>
<p>题目大意：设计一种数据结构，支持inc/dec/getmaxkey/getminkey操作，必须都在O(1)时间内完成。</p>
<p><a href="https://leetcode.com/problems/all-oone-data-structure/description/">https://leetcode.com/problems/all-oone-data-structure/description/</a></p>
<div class="question-description">
<div>
<p>Implement a data structure supporting the following operations:</p>
<ol>
<li>Inc(Key) &#8211; Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a <b>non-empty</b> string.</li>
<li>Dec(Key) &#8211; If Key&#8217;s value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the key does not exist, this function does nothing. Key is guaranteed to be a <b>non-empty</b> string.</li>
<li>GetMaxKey() &#8211; Returns one of the keys with maximal value. If no element exists, return an empty string <code>""</code>.</li>
<li>GetMinKey() &#8211; Returns one of the keys with minimal value. If no element exists, return an empty string <code>""</code>.</li>
</ol>
<p>Challenge: Perform all these in O(1) time complexity.</p>
</div>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-2439" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2018/04/432-ep178.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/04/432-ep178.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/04/432-ep178-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/04/432-ep178-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
</div>
<h1><strong>Solution</strong></h1>
<p>Time complexity: O(1)</p>
<p>Space complexity: O(n), n = # of unique keys</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 32 ms
class AllOne {
public:
  /** Initialize your data structure here. */
  AllOne() {}

  /** Inserts a new key &lt;Key&gt; with value 1. Or increments an existing key by 1. */
  void inc(string key) {
    auto it = m_.find(key);
    
    if (it == m_.end()) {
      if (l_.empty() || l_.front().value != 1) 
        l_.push_front({1, {key}});
      else
        l_.front().keys.insert(key);
      m_[key] = l_.begin();
      return;
    }
    
    auto lit = it-&gt;second;
    
    auto nit = next(lit);
    if (nit == l_.end() || nit-&gt;value != lit-&gt;value + 1)
      nit = l_.insert(nit, {lit-&gt;value + 1, {}});
    nit-&gt;keys.insert(key);
    m_[key] = nit;
    
    remove(lit, key);
  }

  /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
  void dec(string key) {
    auto it = m_.find(key);
    if (it == m_.end()) return;
    
    auto lit = it-&gt;second;
        
    if (lit-&gt;value &gt; 1) {
      auto pit = prev(lit);
      if (lit == l_.begin() || pit-&gt;value != lit-&gt;value - 1)
        pit = l_.insert(lit, {lit-&gt;value - 1, {}});
      pit-&gt;keys.insert(key);
      m_[key] = pit;
    } else {
      // value == 1, remove from the data structure
      m_.erase(key);
    }
    
    remove(lit, key);    
  }

  /** Returns one of the keys with maximal value. */
  string getMaxKey() {
    return l_.empty() ? "" : *l_.back().keys.cbegin();
  }

  /** Returns one of the keys with Minimal value. */
  string getMinKey() {
    return l_.empty() ? "" : *l_.front().keys.cbegin();
  }
private:
  struct Node {  
    int value;
    unordered_set&lt;string&gt; keys;
  };
  
  list&lt;Node&gt; l_;
  unordered_map&lt;string, list&lt;Node&gt;::iterator&gt; m_;
  
  // Remove from old node.
  void remove(list&lt;Node&gt;::iterator it, const string&amp; key) {
    it-&gt;keys.erase(key);
    if (it-&gt;keys.empty())
      l_.erase(it);
  }
};</pre><p></p>
<h1><strong>Related Problems</strong></h1>
<ul>
<li><a href="http://zxi.mytechroad.com/blog/hashtable/leetcode-460-lfu-cache/">[解题报告] LeetCode 460. LFU Cache 花花酱</a></li>
<li><a href="http://zxi.mytechroad.com/blog/hashtable/leetcode-146-lru-cache/">[解题报告] LeetCode 146. LRU Cache O(1)</a></li>
<li><a href="http://zxi.mytechroad.com/blog/hashtable/leetcode-380-insert-delete-getrandom-o1/">[解题报告] LeetCode 380. Insert Delete GetRandom O(1)</a></li>
<li><a href="http://zxi.mytechroad.com/blog/hashtable/leetcode-381-insert-delete-getrandom-o1-duplicates-allowed/">[解题报告] LeetCode 381. Insert Delete GetRandom O(1) &amp;#8211; Duplicates allowed</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/list/leetcode-432-all-oone-data-structure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 225. Implement Stack using Queues</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-225-implement-stack-using-queues/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-225-implement-stack-using-queues/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Tue, 13 Mar 2018 09:59:56 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[easy]]></category>
		<category><![CDATA[queue]]></category>
		<category><![CDATA[stack]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=2084</guid>

					<description><![CDATA[题目大意：用队列来实现栈。 Problem: https://leetcode.com/problems/implement-stack-using-queues/description/ Implement the following operations of a stack using queues. push(x) &#8212; Push element x onto stack. pop() &#8212; Removes the element on&#8230;]]></description>
										<content:encoded><![CDATA[<p>题目大意：用队列来实现栈。</p>
<p><strong>Problem:</strong></p>
<p><a href="https://leetcode.com/problems/implement-stack-using-queues/description/">https://leetcode.com/problems/implement-stack-using-queues/description/</a></p>
<p>Implement the following operations of a stack using queues.</p>
<ul>
<li>push(x) &#8212; Push element x onto stack.</li>
<li>pop() &#8212; Removes the element on top of the stack.</li>
<li>top() &#8212; Get the top element.</li>
<li>empty() &#8212; Return whether the stack is empty.</li>
</ul>
<p><b>Notes:</b></p>
<ul>
<li>You must use <i>only</i> standard operations of a queue &#8212; which means only <code>push to back</code>, <code>peek/pop from front</code>, <code>size</code>, and <code>is empty</code> operations are valid.</li>
<li>Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.</li>
<li>You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).</li>
</ul>
<p><strong>Idea:</strong></p>
<p>Using a single queue, for every push, shift the queue (n &#8211; 1) times such that the last element becomes the first element in the queue.</p>
<p>e.g.</p>
<p>push(1): q: [1]</p>
<p>push(2): q: [1, 2] -&gt; [2, 1]</p>
<p>push(3): q: [2, 1, 3] -&gt; [1, 3, 2] -&gt; [3, 2, 1]</p>
<p>push(4): q: [3, 2, 1, 4] -&gt; [2, 1, 4, 3] -&gt; [1, 4, 3, 2] -&gt; [4, 3, 2, 1]</p>
<p><strong>Solution:</strong></p>
<p>Time complexity:</p>
<p>Push: O(n)</p>
<p>Pop/top/empty: O(1)</p>
<p>Space complexity: O(n)</p>
<p>C++</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 3 ms
class MyStack {
public:
  /** Initialize your data structure here. */
  MyStack() {}

  /** Push element x onto stack. */
  void push(int x) {
    q_.push(x);
    for (int i = 1; i &lt; q_.size(); ++i) {
      q_.push(q_.front());
      q_.pop();
    }
  }

  /** Removes the element on top of the stack and returns that element. */
  int pop() {
    int top = q_.front();
    q_.pop();
    return top;
  }

  /** Get the top element. */
  int top() {
    return q_.front();
  }

  /** Returns whether the stack is empty. */
  bool empty() {
    return q_.empty();
  }
private:
  queue&lt;int&gt; q_;  
};</pre><p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-225-implement-stack-using-queues/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 239. Sliding Window Maximum</title>
		<link>https://zxi.mytechroad.com/blog/heap/leetcode-239-sliding-window-maximum/</link>
					<comments>https://zxi.mytechroad.com/blog/heap/leetcode-239-sliding-window-maximum/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 25 Jan 2018 05:17:37 +0000</pubDate>
				<category><![CDATA[Array]]></category>
		<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[Heap]]></category>
		<category><![CDATA[deque]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[queue]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=1650</guid>

					<description><![CDATA[题目大意：给你一个数组，让你输出移动窗口的最大值。 Problem: https://leetcode.com/problems/sliding-window-maximum/ Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe title="花花酱 LeetCode 239. Sliding Window Maximum - 刷题找工作 EP159" width="500" height="375" src="https://www.youtube.com/embed/2SXqBsTR6a8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>题目大意：给你一个数组，让你输出移动窗口的最大值。</p>
<p><strong>Problem:</strong></p>
<p><a href="https://leetcode.com/problems/sliding-window-maximum/">https://leetcode.com/problems/sliding-window-maximum/</a></p>
<p>Given an array <i>nums</i>, there is a sliding window of size <i>k</i> which is moving from the very left of the array to the very right. You can only see the <i>k</i> numbers in the window. Each time the sliding window moves right by one position.</p>
<p>For example,<br />
Given <i>nums</i> = <code>[1,3,-1,-3,5,3,6,7]</code>, and <i>k</i> = 3.</p><pre class="urvanov-syntax-highlighter-plain-tag">Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7</pre><p>Therefore, return the max sliding window as <code>[3,3,5,5,6,7]</code>.</p>
<p><b>Note: </b><br />
You may assume <i>k</i> is always valid, ie: 1 ≤ k ≤ input array&#8217;s size for non-empty array.</p>
<p><b>Follow up:</b><br />
Could you solve it in linear time?</p>
<p><ins class="adsbygoogle" style="display: block; text-align: center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-2404451723245401" data-ad-slot="7983117522"> </ins></p>
<p><strong>Idea:</strong></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1657" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1656" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/01/239-ep159-2-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></p>
<p>&nbsp;</p>
<h1><strong>Solution 1: Brute Force</strong></h1>
<p>Time complexity: O((n &#8211; k + 1) * k)</p>
<p>Space complexity: O(1)</p>
<p><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 180 ms
class Solution {
public:
  vector&lt;int&gt; maxSlidingWindow(vector&lt;int&gt;&amp; nums, int k) {    
    vector&lt;int&gt; ans;
    for (int i = k - 1; i &lt; nums.size(); ++i) {
      ans.push_back(*max_element(nums.begin() + i - k + 1, nums.begin() + i + 1));
    }
    return ans;
  }
};</pre><p></div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 80 ms
class Solution {
  public int[] maxSlidingWindow(int[] nums, int k) {
    if (k == 0) return new int[0];
    
    int[] ans = new int[nums.length - k + 1];    
    for (int i = k - 1; i &lt; nums.length; ++i) {
      int maxNum = nums[i];
      for (int j = 1; j &lt; k; ++j)
        if (nums[i - j] &gt; maxNum) maxNum = nums[i - j];
      ans[i - k + 1] = maxNum;
    }
    return ans;
  }
}</pre><p></div><h2 class="tabtitle">Python</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">"""
Author: Huahua
Running time: 1044 ms
"""
class Solution:
  def maxSlidingWindow(self, nums, k):
    if not nums: return []    
    return [max(nums[i:i+k]) for i in range(len(nums) - k + 1)]</pre><p></div></div></p>
<h1><strong>Solution 2: BST</strong></h1>
<p>Time complexity: O((n &#8211; k + 1) * logk)</p>
<p>Space complexity: O(k)</p>
<p><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 82 ms
class Solution {
public:
  vector&lt;int&gt; maxSlidingWindow(vector&lt;int&gt;&amp; nums, int k) {
    vector&lt;int&gt; ans;
    if (nums.empty()) return ans;
    multiset&lt;int&gt; window(nums.begin(), nums.begin() + k - 1);
    for (int i = k - 1; i &lt; nums.size(); ++i) {
      window.insert(nums[i]);
      ans.push_back(*window.rbegin());
      if (i - k + 1 &gt;= 0)
        window.erase(window.equal_range(nums[i - k + 1]).first);      
    }
    return ans;
  }
};</pre><p></div></div></p>
<h1><strong>Solution 3: Monotonic Queue</strong></h1>
<p>Time complexity: O(n)</p>
<p>Space complexity: O(k)</p>
<p><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 70 ms
class MonotonicQueue {
public:
  void push(int e) {
    while(!data_.empty() &amp;&amp; e &gt; data_.back()) data_.pop_back();
    data_.push_back(e);
  } 
  
  void pop() {
    data_.pop_front();
  }
  
  int max() const { return data_.front(); }
private:
  deque&lt;int&gt; data_;
};

class Solution {
public:
  vector&lt;int&gt; maxSlidingWindow(vector&lt;int&gt;&amp; nums, int k) {
    MonotonicQueue q;
    vector&lt;int&gt; ans;
        
    for (int i = 0; i &lt; nums.size(); ++i) {
      q.push(nums[i]);
      if (i - k + 1 &gt;= 0) {
        ans.push_back(q.max());
        if (nums[i - k + 1] == q.max()) q.pop();
      }      
    }
    return ans;
  }
};</pre><p></div><h2 class="tabtitle">C++ V2</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 65 ms
class Solution {
public:
  vector&lt;int&gt; maxSlidingWindow(vector&lt;int&gt;&amp; nums, int k) {
    deque&lt;int&gt; index;
    vector&lt;int&gt; ans;
        
    for (int i = 0; i &lt; nums.size(); ++i) {
      while (!index.empty() &amp;&amp; nums[i] &gt;= nums[index.back()]) index.pop_back();
      index.push_back(i);      
      if (i - k + 1 &gt;= 0) ans.push_back(nums[index.front()]);
      if (i - k + 1 &gt;= index.front()) index.pop_front();
    }
    return ans;
  }
};</pre><p></div><h2 class="tabtitle">C++ V3</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 67 ms
class Solution {
public:
  vector&lt;int&gt; maxSlidingWindow(vector&lt;int&gt;&amp; nums, int k) {
    deque&lt;int&gt; q;
    vector&lt;int&gt; ans;
        
    for (int i = 0; i &lt; nums.size(); ++i) {
      while (!q.empty() &amp;&amp; nums[i] &gt; q.back()) q.pop_back();
      q.push_back(nums[i]);
      const int s = i - k + 1;
      if (s &lt; 0) continue;      
      ans.push_back(q.front());
      if (nums[s] == q.front()) q.pop_front();
    }
    return ans;
  }
};</pre><p></div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 19 ms
class Solution {
  public int[] maxSlidingWindow(int[] nums, int k) {
    if (k == 0) return nums;
    
    int[] ans = new int[nums.length - k + 1];
    Deque&lt;Integer&gt; indices = new LinkedList&lt;&gt;();
    
    for (int i = 0; i &lt; nums.length; ++i) {
      while (indices.size() &gt; 0 &amp;&amp; nums[i] &gt;= nums[indices.getLast()])
        indices.removeLast();
      
      indices.addLast(i);
      if (i - k + 1 &gt;= 0) ans[i - k + 1] = nums[indices.getFirst()];
      if (i - k + 1 &gt;= indices.getFirst()) indices.removeFirst();
    }
             
    return ans;
  }
}</pre><p></div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">"""
Author: Huahua
Running time: 238 ms
"""
class MaxQueue:
  def __init__(self):
    self.q_ = collections.deque()
  
  def push(self, e):
    while self.q_ and e &gt; self.q_[-1]: self.q_.pop()
    self.q_.append(e)
  
  def pop(self):
    self.q_.popleft()
  
  def max(self):
    return self.q_[0]
    
class Solution:
  def maxSlidingWindow(self, nums, k):
    q = MaxQueue()
    ans = []
    for i in range(len(nums)):
      q.push(nums[i])
      if i &gt;= k - 1: 
        ans.append(q.max())
        if nums[i - k + 1] == q.max(): q.pop()
    return ans</pre><p></div><h2 class="tabtitle">Python3 V2</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">"""
Author: Huahua
Running time: 193 ms
"""
class Solution:
  def maxSlidingWindow(self, nums, k):
    indices = collections.deque()
    ans = []
    for i in range(len(nums)):
      while indices and nums[i] &gt;= nums[indices[-1]]: indices.pop()
      indices.append(i)
      if i &gt;= k - 1: ans.append(nums[indices[0]])
      if i - k + 1 == indices[0]: indices.popleft()
    return ans</pre><p></div></div></p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/heap/leetcode-239-sliding-window-maximum/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 307. Range Sum Query &#8211; Mutable</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/#comments</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 04 Jan 2018 05:27:14 +0000</pubDate>
				<category><![CDATA[Array]]></category>
		<category><![CDATA[Bit]]></category>
		<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[fenwick tree]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[prefix sum]]></category>
		<category><![CDATA[range sum]]></category>
		<category><![CDATA[segment tree]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=1482</guid>

					<description><![CDATA[题目大意：给你一个数组，让你求一个范围之内所有元素的和，数组元素可以更改。 Problem: Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val. Example: [crayon-69b1286351b07621244476/]&#8230;]]></description>
										<content:encoded><![CDATA[<p>题目大意：给你一个数组，让你求一个范围之内所有元素的和，数组元素可以更改。</p>
<p><strong>Problem:</strong></p>
<p>Given an integer array <i>nums</i>, find the sum of the elements between indices <i>i</i> and <i>j</i> (<i>i</i> ≤ <i>j</i>), inclusive.</p>
<p>The <i>update(i, val)</i> function modifies <i>nums</i> by updating the element at index <i>i</i> to <i>val</i>.</p>
<p><b>Example:</b></p>
<pre class="urvanov-syntax-highlighter-plain-tag">Given nums = [1, 3, 5]

sumRange(0, 2) -&gt; 9
update(1, 2)
sumRange(0, 2) -&gt; 8</pre>
<p><b>Note:</b></p>
<ol>
<li>The array is only modifiable by the <i>update</i> function.</li>
<li>You may assume the number of calls to <i>update</i> and <i>sumRange</i> function is distributed evenly.</li>
</ol>
<p><strong>Idea:</strong></p>
<p>Fenwick Tree</p>
<p><strong>Solution:</strong></p>
<p>C++</p>
<p>Time complexity:</p>
<p>init O(nlogn)</p>
<p>query: O(logn)</p>
<p>update: O(logn)<br /><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p>
<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 83 ms
class FenwickTree {    
public:
    FenwickTree(int n): sums_(n + 1, 0) {}
    
    void update(int i, int delta) {
        while (i &lt; sums_.size()) {
            sums_[i] += delta;
            i += lowbit(i);
        }
    }
    
    int query(int i) const {        
        int sum = 0;
        while (i &gt; 0) {
            sum += sums_[i];
            i -= lowbit(i);
        }
        return sum;
    }
private:
    static inline int lowbit(int x) { return x &amp; (-x); }
    vector&lt;int&gt; sums_;
};

class NumArray {
public:
    NumArray(vector&lt;int&gt; nums): nums_(std::move(nums)), tree_(nums_.size()) {
        for (int i = 0; i &lt; nums_.size(); ++i)
            tree_.update(i + 1, nums_[i]);
    }
    
    void update(int i, int val) {
        tree_.update(i + 1, val - nums_[i]);
        nums_[i] = val;
    }
    
    int sumRange(int i, int j) {
        return tree_.query(j + 1) - tree_.query(i);
    }
private:
    vector&lt;int&gt; nums_;
    FenwickTree tree_;
};</pre>

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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 130 ms
class NumArray {
    FenwickTree tree_;
    int[] nums_;
    public NumArray(int[] nums) {
        nums_ = nums;
        tree_ = new FenwickTree(nums.length);
        for (int i = 0; i &lt; nums.length; ++i)
            tree_.update(i + 1, nums[i]);
    }
    
    public void update(int i, int val) {
        tree_.update(i + 1, val - nums_[i]);
        nums_[i] = val;
    }
    
    public int sumRange(int i, int j) {
        return tree_.query(j + 1) - tree_.query(i);
    }
class FenwickTree {
    int sums_[];
    public FenwickTree(int n) {
        sums_ = new int[n + 1];
    }
    
    public void update(int i, int delta) {
        while (i &lt; sums_.length) {
            sums_[i] += delta;
            i += i &amp; -i;
        }
    }
    
    public int query(int i) {
        int sum = 0;
        while (i &gt; 0) {
            sum += sums_[i];
            i -= i &amp; -i;
        }
        return sum;
    }
}
}</pre>

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

<pre class="urvanov-syntax-highlighter-plain-tag">"""
Author: Huahua
Running time: 192 ms (&lt; 90.00%)
"""
class FenwickTree:
    def __init__(self, n):
        self._sums = [0 for _ in range(n + 1)]
        
    def update(self, i, delta):
        while i &lt; len(self._sums):
            self._sums[i] += delta
            i += i &amp; -i
    
    def query(self, i):
        s = 0
        while i &gt; 0:
            s += self._sums[i]
            i -= i &amp; -i
        return s
    
class NumArray:

    def __init__(self, nums):
        self._nums = nums
        self._tree = FenwickTree(len(nums))
        for i in range(len(nums)):
            self._tree.update(i + 1, nums[i])

    def update(self, i, val):
        self._tree.update(i + 1, val - self._nums[i])
        self._nums[i] = val
        

    def sumRange(self, i, j):
        return self._tree.query(j + 1) - self._tree.query(i)</pre>
</div></div>


<h2 class="wp-block-heading">Solution 2: Segment Tree</h2>



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

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua, running time: 24 ms
class SegmentTreeNode {
public:
  SegmentTreeNode(int start, int end, int sum,
                  SegmentTreeNode* left = nullptr,
                  SegmentTreeNode* right = nullptr): 
    start(start),
    end(end),
    sum(sum),
    left(left),
    right(right){}      
  SegmentTreeNode(const SegmentTreeNode&amp;) = delete;
  SegmentTreeNode&amp; operator=(const SegmentTreeNode&amp;) = delete;
  ~SegmentTreeNode() {
    delete left;
    delete right;
    left = right = nullptr;
  }
  
  int start;
  int end;
  int sum;
  SegmentTreeNode* left;
  SegmentTreeNode* right;
};

class NumArray {
public:
  NumArray(vector&lt;int&gt; nums) {
    nums_.swap(nums);
    if (!nums_.empty())
      root_.reset(buildTree(0, nums_.size() - 1));
  }

  void update(int i, int val) {
    updateTree(root_.get(), i, val);
  }

  int sumRange(int i, int j) {
    return sumRange(root_.get(), i, j);
  }
private:
  vector&lt;int&gt; nums_;
  std::unique_ptr&lt;SegmentTreeNode&gt; root_;
  
  SegmentTreeNode* buildTree(int start, int end) {  
    if (start == end) {      
      return new SegmentTreeNode(start, end, nums_[start]);
    }
    int mid = start + (end - start) / 2;
    auto left = buildTree(start, mid);
    auto right = buildTree(mid + 1, end);
    auto node = new SegmentTreeNode(start, end, left-&gt;sum + right-&gt;sum, left, right);    
    return node;
  }
  
  void updateTree(SegmentTreeNode* root, int i, int val) {
    if (root-&gt;start == i &amp;&amp; root-&gt;end == i) {
      root-&gt;sum = val;
      return;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (i &lt;= mid) {
      updateTree(root-&gt;left, i, val);
    } else {      
      updateTree(root-&gt;right, i, val);
    }
    root-&gt;sum = root-&gt;left-&gt;sum + root-&gt;right-&gt;sum;
  }
  
  int sumRange(SegmentTreeNode* root, int i, int j) {    
    if (i == root-&gt;start &amp;&amp; j == root-&gt;end) {
      return root-&gt;sum;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (j &lt;= mid) {
      return sumRange(root-&gt;left, i, j);
    } else if (i &gt; mid) {
      return sumRange(root-&gt;right, i, j);
    } else {
      return sumRange(root-&gt;left, i, mid) + sumRange(root-&gt;right, mid + 1, j);
    }
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode Disjoint set / Union Find Forest SP1</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/sp1-union-find-set/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/sp1-union-find-set/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 30 Nov 2017 01:49:27 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[SP]]></category>
		<category><![CDATA[tree]]></category>
		<category><![CDATA[union find]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=1039</guid>

					<description><![CDATA[Disjoint-set/Union-find Forest Find(x): find the root/cluster-id of x Union(x, y): merge two clusters Check whether two elements are in the same set or not in&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe loading="lazy" title="花花酱 Disjoint-set/Union-find Forest - 刷题找工作 SP1" width="500" height="375" src="https://www.youtube.com/embed/VJnUwsE4fWA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p><span style="font-weight: 400;">Disjoint-set/Union-find Forest</span></p>
<p><span style="font-weight: 400;">Find(x): find the root/cluster-id of x</span></p>
<p><span style="font-weight: 400;">Union(x, y): merge two clusters</span></p>
<p><span style="font-weight: 400;">Check whether two elements are in the same set or not in O(1)</span><span style="font-weight: 400;">*</span><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">Find: O(ɑ(n))</span><span style="font-weight: 400;">*</span><span style="font-weight: 400;"> ≈ O(1)</span></p>
<p><span style="font-weight: 400;">Union: </span><span style="font-weight: 400;">O(ɑ(n))</span><span style="font-weight: 400;">*</span><span style="font-weight: 400;"> ≈ O(1)</span></p>
<p><span style="font-weight: 400;">Space: O(n)</span></p>
<p><span style="font-weight: 400;">Without optimization: Find: O(n)</span></p>
<p><span style="font-weight: 400;">Two key optimizations:</span></p>
<ol>
<li style="font-weight: 400;"><span style="font-weight: 400;">Path compression: make tree flat</span></li>
<li style="font-weight: 400;"><span style="font-weight: 400;">Union by rank: merge low rank tree to high rank one</span></li>
</ol>
<p><span style="font-weight: 400;">*: amortized</span></p>
<p><span style="font-weight: 400;">ɑ(.): inverse Ackermann function</span></p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-1.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1046" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-1.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-1-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<p>&nbsp;</p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-2.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1045" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-2-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-3.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1044" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-3.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/11/sp1-3-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<h1>Implementations:</h1>
<p><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class UnionFindSet {
public:
    UnionFindSet(int n) {
        ranks_ = vector&lt;int&gt;(n + 1, 0);        
        parents_ = vector&lt;int&gt;(n + 1, 0);                
        
        for (int i = 0; i &lt; parents_.size(); ++i)
            parents_[i] = i;
    }
    
    // Merge sets that contains u and v.
    // Return true if merged, false if u and v are already in one set.
    bool Union(int u, int v) {
        int pu = Find(u);
        int pv = Find(v);
        if (pu == pv) return false;
        
        // Meger low rank tree into high rank tree
        if (ranks_[pv] &lt; ranks_[pu])
            parents_[pv] = pu;           
        else if (ranks_[pu] &lt; ranks_[pv])
            parents_[pu] = pv;
        else {
            parents_[pv] = pu;
            ranks_[pu] += 1;
        }
        
        return true;
    }
    
    // Get the root of u.
    int Find(int u) {        
        // Compress the path during traversal
        if (u != parents_[u])
            parents_[u] = Find(parents_[u]);        
        return parents_[u];
    }
private:
    vector&lt;int&gt; parents_;
    vector&lt;int&gt; ranks_;
};</pre><p></div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class UnionFindSet {
  private int[] parents_;
  private int[] ranks_;

  public UnionFindSet(int n) {
      parents_ = new int[n + 1];
      ranks_ = new int[n + 1];
      for (int i = 0; i &lt; parents_.length; ++i) {
          parents_[i] = i;
          ranks_[i] = 1;
      }
  }

  public boolean Union(int u, int v) {
      int pu = Find(u);
      int pv = Find(v);
      if (pu == pv) return false;

      if (ranks_[pv] &gt; ranks_[pu])
          parents_[pu] = pv;           
      else if (ranks_[pu] &gt; ranks_[pv])
          parents_[pv] = pu;
      else {
          parents_[pv] = pu;
          ranks_[pu] += 1;
      }

      return true;
  }

  public int Find(int u) {
      while (parents_[u] != u) {
          parents_[u] = parents_[parents_[u]];
          u = parents_[u];
      }
      return u;
  }
}</pre><p></div><h2 class="tabtitle">Python</h2>
<div class="tabcontent">
</p><pre class="urvanov-syntax-highlighter-plain-tag">"""
Author: Huahua
"""
class UnionFindSet:
    def __init__(self, n):
        self._parents = [i for i in range(n + 1)]
        self._ranks = [1 for i in range(n + 1)]
    
    def find(self, u):
        while u != self._parents[u]:
            self._parents[u] = self._parents[self._parents[u]]
            u = self._parents[u]
        return u
    
    def union(self, u, v):
        pu, pv = self.find(u), self.find(v)
        if pu == pv: return False
        
        if self._ranks[pu] &lt; self._ranks[pv]:
            self._parents[pu] = pv
        elif self._ranks[pu] &gt; self._ranks[pv]:
            self._parents[pv] = pu
        else:        
            self._parents[pv] = pu
            self._ranks[pu] += 1
        
        return True</pre><p></div></div></p>
<h1>Union-Find Problems</h1>
<ul>
<li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-399-evaluate-division/">花花酱 LeetCode 399. Evaluate Division</a></li>
<li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-547-friend-circles/">花花酱 LeetCode 547. Friend Circles</a></li>
<li><a href="https://zxi.mytechroad.com/blog/hashtable/leetcode-737-sentence-similarity-ii/">花花酱 LeetCode 737. Sentence Similarity II</a></li>
<li><a href="https://zxi.mytechroad.com/blog/tree/leetcode-684-redundant-connection/">花花酱 LeetCode 684. Redundant Connection</a></li>
<li><a href="https://zxi.mytechroad.com/blog/graph/leetcode-685-redundant-connection-ii/">花花酱 LeetCode 685. Redundant Connection II</a></li>
<li><a href="https://zxi.mytechroad.com/blog/string/leetcode-839-similar-string-groups/">花花酱 LeetCode 839. Similar String Groups</a></li>
</ul>
<h1><strong>References</strong></h1>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure">https://en.wikipedia.org/wiki/Disjoint-set_data_structure</a></li>
<li><a href="https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/UnionFind.pdf">https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/UnionFind.pdf</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/sp1-union-find-set/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 715. Range Module</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/leetcode-715-range-module/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/leetcode-715-range-module/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 22 Oct 2017 23:29:45 +0000</pubDate>
				<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[Geometry]]></category>
		<category><![CDATA[Hard]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[range]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=679</guid>

					<description><![CDATA[Problem: A Range Module is a module that tracks ranges of numbers. Your task is to design and implement the following interfaces in an efficient&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe loading="lazy" title="花花酱 LeetCode. 715 Range Module - 刷题找工作 EP96" width="500" height="375" src="https://www.youtube.com/embed/pcpB9ux3RrQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p><strong>Problem:</strong></p>
<p>A Range Module is a module that tracks ranges of numbers. Your task is to design and implement the following interfaces in an efficient manner.</p>
<p>&nbsp;</p>
<ul>
<li><code>addRange(int left, int right)</code> Adds the half-open interval <code>[left, right)</code>, tracking every real number in that interval. Adding an interval that partially overlaps with currently tracked numbers should add any numbers in the interval <code>[left, right)</code> that are not already tracked.</li>
<li><code>queryRange(int left, int right)</code> Returns true if and only if every real number in the interval <code>[left, right)</code> is currently being tracked.</li>
<li><code>removeRange(int left, int right)</code> Stops tracking every real number currently being tracked in the interval <code>[left, right)</code>.</li>
</ul>
<p><b>Example 1:</b></p><pre class="urvanov-syntax-highlighter-plain-tag">addRange(10, 20): null
removeRange(14, 16): null
queryRange(10, 14): true (Every number in [10, 14) is being tracked)
queryRange(13, 15): false (Numbers like 14, 14.03, 14.17 in [13, 15) are not being tracked)
queryRange(16, 17): true (The number 16 in [16, 17) is still being tracked, despite the remove operation)</pre><p><b>Note:</b></p>
<ul>
<li>A half open interval <code>[left, right)</code> denotes all real numbers <code>left &lt;= x &lt; right</code>.</li>
<li><code>0 &lt; left &lt; right &lt; 10^9</code> in all calls to <code>addRange, queryRange, removeRange</code>.</li>
<li>The total number of calls to <code>addRange</code> in a single test case is at most <code>1000</code>.</li>
<li>The total number of calls to <code>queryRange</code> in a single test case is at most <code>5000</code>.</li>
<li>The total number of calls to <code>removeRange</code> in a single test case is at most <code>1000</code>.</li>
</ul>
<p><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><br />
<ins class="adsbygoogle" style="display: block; text-align: center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-2404451723245401" data-ad-slot="7983117522"></ins><br />
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script></p>
<p><strong>Idea:</strong></p>
<p>map / ordered ranges</p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-689" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-1-624x351.png 624w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a>  <a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-688" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-2-624x351.png 624w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-687" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-3-624x351.png 624w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<p><a href="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-686" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/10/715-ep96-4-624x351.png 624w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<p>&nbsp;</p>
<p><strong>Solution:</strong></p>
<p>C++ / vector</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Runtime: 276 ms
class RangeModule {
public:
    RangeModule() {}
    
    void addRange(int left, int right) {
        vector&lt;pair&lt;int, int&gt;&gt; new_ranges;
        bool inserted = false;
        for (const auto&amp; kv : ranges_) {            
            if (kv.first &gt; right &amp;&amp; !inserted) {
                new_ranges.emplace_back(left, right);
                inserted = true;
            }
            if (kv.second &lt; left || kv.first &gt; right) { 
                new_ranges.push_back(kv);
            } else {
                left = min(left, kv.first);
                right = max(right, kv.second);
            }
        }       
        if (!inserted) new_ranges.emplace_back(left, right);       
        ranges_.swap(new_ranges);
    }
    
    bool queryRange(int left, int right) {
        const int n = ranges_.size();
        int l = 0;
        int r = n - 1;
        // Binary search
        while (l &lt;= r) {
            int m = l + (r - l) / 2;
            if (ranges_[m].second &lt; left)
                l = m + 1;
            else if (ranges_[m].first &gt; right)
                r = m - 1;
            else
                return ranges_[m].first &lt;= left &amp;&amp; ranges_[m].second &gt;= right;
        }
        return false;
    }
    
    void removeRange(int left, int right) {
        vector&lt;pair&lt;int, int&gt;&gt; new_ranges;        
        for (const auto&amp; kv : ranges_) {
            if (kv.second &lt;= left || kv.first &gt;= right) {
                new_ranges.push_back(kv);
            } else {
                if (kv.first &lt; left)
                    new_ranges.emplace_back(kv.first, left);
                if (kv.second &gt; right)
                    new_ranges.emplace_back(right, kv.second);
            }        
        }
        ranges_.swap(new_ranges);
    }
    vector&lt;pair&lt;int, int&gt;&gt; ranges_;
};</pre><p>C++ / map</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Runtime: 199 ms
class RangeModule {
public:
    RangeModule() {}
    
    void addRange(int left, int right) {
        IT l, r;
        getOverlapRanges(left, right, l, r);
        // At least one range overlapping with [left, right)
        if (l != r) {
            // Merge intervals into [left, right)
            auto last = r; --last;
            left = min(left, l-&gt;first);            
            right = max(right, last-&gt;second);
            // Remove all overlapped ranges
            ranges_.erase(l, r);
        }
        // Add a new/merged range
        ranges_[left] = right;
    }
    
    bool queryRange(int left, int right) {
        IT l, r;
        getOverlapRanges(left, right, l, r);
        // No overlapping range
        if (l == r) return false;
        return l-&gt;first &lt;= left &amp;&amp; l-&gt;second &gt;= right;
    }
    
    void removeRange(int left, int right) {
        IT l, r;
        getOverlapRanges(left, right, l, r);
        // No overlapping range
        if (l == r) return;
        auto last = r; --last;
        int start = min(left, l-&gt;first);        
        int end = max(right, last-&gt;second);
        // Delete overlapping ranges        
        ranges_.erase(l, r);
        if (start &lt; left) ranges_[start] = left;
        if (end &gt; right) ranges_[right] = end;
    }
private:
    typedef map&lt;int, int&gt;::iterator IT;
    map&lt;int, int&gt; ranges_;
    void getOverlapRanges(int left, int right, IT&amp; l, IT&amp; r) {
        l = ranges_.upper_bound(left);
        r = ranges_.upper_bound(right);
        if (l != ranges_.begin())
            if ((--l)-&gt;second &lt; left) l++;
    }
};</pre><p><strong>Related Problems:</strong></p>
<ul>
<li><a href="http://zxi.mytechroad.com/blog/geometry/leetcode-57-insert-interval/">[解题报告] LeetCode 57. Insert Interval</a></li>
<li><a href="http://zxi.mytechroad.com/blog/geometry/leetcode-56-merge-intervals/">[解题报告] LeetCode 56. Merge Intervals</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/leetcode-715-range-module/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
