<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>🥽 Understanding computer science fundamentals | The Commonplace Book</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/</link><atom:link href="https://www.siddeshsambasivam.com/notes/cs-concepts/index.xml" rel="self" type="application/rss+xml"/><description>🥽 Understanding computer science fundamentals</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><copyright>Siddesh Sambasivam Suseela © **2024**</copyright><lastBuildDate>Thu, 07 Mar 2024 00:00:00 +0000</lastBuildDate><image><url>https://www.siddeshsambasivam.com/notes/cs-concepts/featured.png</url><title>🥽 Understanding computer science fundamentals</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/</link></image><item><title>0. Reading list</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/0.-reading-list/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/0.-reading-list/</guid><description>&lt;h2 id="a-system-design-related-articles">A. System Design Related articles&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;input checked="" disabled="" type="checkbox"> &lt;a href="https://ravisystemdesign.substack.com/p/system-design-fundamentals?utm_source=%2Fprofile%2F17018935-ravi-tandon&amp;amp;utm_medium=reader2" target="_blank" rel="noopener">System Design: Fundamentals&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;input checked="" disabled="" type="checkbox"> &lt;a href="https://ravisystemdesign.substack.com/p/principles-of-the-microservice-architecture?utm_source=%2Fprofile%2F17018935-ravi-tandon&amp;amp;utm_medium=reader2" target="_blank" rel="noopener">Principles Of The Microservice Architecture&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;input disabled="" type="checkbox"> &lt;a href="https://ravisystemdesign.substack.com/p/interview-preparation-designing-a?utm_source=%2Fprofile%2F17018935-ravi-tandon&amp;amp;utm_medium=reader2" target="_blank" rel="noopener">Designing A Scalable Notification Service&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;input disabled="" type="checkbox"> &lt;a href="https://ravisystemdesign.substack.com/p/interview-prep-designing-a-distributed?utm_source=%2Fprofile%2F17018935-ravi-tandon&amp;amp;utm_medium=reader2" target="_blank" rel="noopener">Designing A Distributed Cache&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="b-courses-to-take">B. Courses to take&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;input disabled="" type="checkbox"> &lt;a href="https://nptel.ac.in/courses/106106238" target="_blank" rel="noopener">Applied accelerated Artificial Intelligence, IIT Madras&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;input disabled="" type="checkbox"> &lt;a href="https://nptel.ac.in/courses/106105184" target="_blank" rel="noopener">Blockchain Architecture Design and Use Cases&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>1. Computer fundamentals</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/1.-memory-and-process-related-stuff/</link><pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/1.-memory-and-process-related-stuff/</guid><description>&lt;h3 id="1-endianness">1. Endianness&lt;/h3>
&lt;p>The order or sequence in which the bytes of a data is stored in a computer memory. It is expressed as &lt;code>big-endian (BE)&lt;/code> or &lt;code>little-endian (LE)&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>&lt;code>Big-endian&lt;/code>: The most significant byte (MSB) is stored at the smallest memory address.&lt;/li>
&lt;li>&lt;code>Little-endian&lt;/code>: The least significant byte (LSB) is stored at the smallest memory address.&lt;/li>
&lt;/ol>
&lt;h3 id="2-stack--heap-memory-allocation-and-management-in-python">2. Stack &amp;amp; Heap: Memory Allocation and management in python&lt;/h3>
&lt;p>When a variable is declared, for example &lt;code>x=10&lt;/code> and &lt;code>x=y&lt;/code> both have the same value memory, i.e both variable points to the same object. Python optimizes memory utilisation by allocating the same object reference to a new variable if object already exists in memory with same value.&lt;/p>
&lt;p>Memory address stored by a variable can be found using &lt;code>id()&lt;/code>.&lt;/p>
&lt;p>The order of memory allocation in RAM is as follows (Low to high),&lt;/p>
&lt;figure id="figure-httpscoursesengrillinoiseducs225sp2022resourcesstack-heap">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="https://courses.engr.illinois.edu/cs225/sp2022/resources/stack-heap/" srcset="
/media/leetcode/memory_huab65d61ff88cd4d0bf3d406469d7b8a0_24928_e15c97ff13cb45bcf7622c01b54ffae3.webp 400w,
/media/leetcode/memory_huab65d61ff88cd4d0bf3d406469d7b8a0_24928_4538a8590932c58371c1ed06db31601d.webp 760w,
/media/leetcode/memory_huab65d61ff88cd4d0bf3d406469d7b8a0_24928_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/memory_huab65d61ff88cd4d0bf3d406469d7b8a0_24928_e15c97ff13cb45bcf7622c01b54ffae3.webp"
width="250px"
height="368"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
&lt;a href="https://courses.engr.illinois.edu/cs225/sp2022/resources/stack-heap/">https://courses.engr.illinois.edu/cs225/sp2022/resources/stack-heap/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;p>Heap is responsible to store all the values. A stack stores hold the references to the objects in the heap.&lt;/p>
&lt;p>The name &lt;code>heap&lt;/code> and &lt;code>stack&lt;/code> does not have any relation to the data structure.&lt;/p>
&lt;h3 id="3-processes-and-threads">3. Processes and Threads&lt;/h3>
&lt;p>A &lt;strong>process&lt;/strong> is a program that is currently under execution, whereas a &lt;strong>thread&lt;/strong> is an execution entity that reside within a process that can be scheduled for execution. &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p>
&lt;p>A thread is an &lt;code>execution unit&lt;/code> with its own stack and set of registers that reside in a &lt;u>process&lt;/u>. A thread always belongs to exactly one process.&lt;/p>
&lt;p>&lt;em>Threads are also known as light-weight processes.&lt;/em>&lt;/p>
&lt;figure id="figure-difference-bw-single--multi-threaded-process">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Difference b/w single &amp;amp; multi-threaded process" srcset="
/media/leetcode/pro_thred_huf65d63a0fcc8a1ce13db2db27d67e771_100012_808b054492e3ebfa2064a45e104d0d4f.webp 400w,
/media/leetcode/pro_thred_huf65d63a0fcc8a1ce13db2db27d67e771_100012_5a9a58a23919d518449acafb51452500.webp 760w,
/media/leetcode/pro_thred_huf65d63a0fcc8a1ce13db2db27d67e771_100012_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/pro_thred_huf65d63a0fcc8a1ce13db2db27d67e771_100012_808b054492e3ebfa2064a45e104d0d4f.webp"
width="760"
height="397"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Difference b/w single &amp;amp; multi-threaded process
&lt;/figcaption>&lt;/figure>
&lt;p>In a multi-threaded process, each thread has its own stack and registers but shares the same memory. This lets access to code segments, files and data be shared among threads.&lt;/p>
&lt;h3 id="4-mutexes-and-semaphores">4. Mutexes and Semaphores&lt;/h3>
&lt;h3 id="5global-interpreter-lock-gil">5.Global Interpreter Lock (GIL)&lt;/h3>
&lt;h3 id="references">References&lt;/h3>
&lt;section class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1" role="doc-endnote">
&lt;p>&lt;a href="https://afteracademy.com/blog/what-is-a-thread-in-os-and-what-are-the-differences-between-a-process-and-a-thread" target="_blank" rel="noopener">https://afteracademy.com/blog/what-is-a-thread-in-os-and-what-are-the-differences-between-a-process-and-a-thread&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/section></description></item><item><title>2. Analyzing Time Complexities</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/2.-analyzing-time-complexities/</link><pubDate>Wed, 10 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/2.-analyzing-time-complexities/</guid><description>&lt;h2 id="data-structures">Data Structures&lt;/h2>
&lt;h3 id="1-array">1. Array&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Operation&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Insert&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Delete&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Access&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="2-linked-list">2. Linked List&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Operation&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Insert&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Delete&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Access&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="3-heap">3. Heap&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Operation&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Insert&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Delete&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;td style="text-align:center">O(log n)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Heapify&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Access largest/smallest&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="4-hash-table">4. Hash Table&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Operation&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Insertion&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Deletion&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Access&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="5-binary-search-tree">5. Binary search tree&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Operation&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Insert&lt;/td>
&lt;td style="text-align:center">O(logn)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Delete&lt;/td>
&lt;td style="text-align:center">O(logn)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">Access&lt;/td>
&lt;td style="text-align:center">O(logn)&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="algorithms">Algorithms&lt;/h2>
&lt;h3 id="1-sorting">1. Sorting&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Algorithm&lt;/th>
&lt;th style="text-align:center">Best case&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Bubble sort&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(n^2)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Quick sort&lt;/td>
&lt;td style="text-align:center">O(nlogn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(n^2)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Insertion sort&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(n^2)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Merge sort&lt;/td>
&lt;td style="text-align:center">O(nlogn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(nlogn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Heap sort&lt;/td>
&lt;td style="text-align:center">O(nlogn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(nlogn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="2-searching">2. Searching&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Algorithm&lt;/th>
&lt;th style="text-align:center">Best case&lt;/th>
&lt;th style="text-align:center">Average case&lt;/th>
&lt;th style="text-align:center">Worst case&lt;/th>
&lt;th style="text-align:center">Amortized&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Linear&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(n)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Binary&lt;/td>
&lt;td style="text-align:center">O(1)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;td style="text-align:center">O(logn)&lt;/td>
&lt;td style="text-align:center">-&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table></description></item><item><title>3. Graphs and advanced graphs</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/3.-graphs-and-advanced-graphs/</link><pubDate>Fri, 29 Jul 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/3.-graphs-and-advanced-graphs/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-general-introduction">A. General Introduction&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#i-adjacency-list">I. Adjacency List&lt;/a>&lt;/li>
&lt;li>&lt;a href="#ii-adjacency-matrix">II. Adjacency Matrix&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#b-leetcode-problems">B. Leetcode problems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#133-clone-graph">133. Clone Graph&lt;/a>&lt;/li>
&lt;li>&lt;a href="#994-rotting-oranges">994. Rotting Oranges&lt;/a>&lt;/li>
&lt;li>&lt;a href="#684-redundant-connection">684. Redundant Connection&lt;/a>&lt;/li>
&lt;li>&lt;a href="#743-network-delay-time">743. Network Delay Time&lt;/a>&lt;/li>
&lt;li>&lt;a href="#1584-min-cost-to-connect-all-points">1584. Min Cost to Connect All Points&lt;/a>&lt;/li>
&lt;li>&lt;a href="#778-swim-in-rising-water">778. Swim in Rising Water&lt;/a>&lt;/li>
&lt;li>&lt;a href="#787-cheapest-flights-within-k-stops">787. Cheapest Flights Within K Stops&lt;/a>&lt;/li>
&lt;li>&lt;a href="#127-word-ladder">127. Word Ladder&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;p>A &lt;strong>graph&lt;/strong> is a collection of &lt;em>nodes&lt;/em> and &lt;em>edges&lt;/em>. Each node is connected to other nodes by edges. The connection between nodes can either be &lt;em>directed&lt;/em> or &lt;em>undirected&lt;/em>. Furthermore, each edge can even have a &lt;em>weight&lt;/em>.&lt;/p>
&lt;p>A graph can be represented in a number of ways. I have listed two common representations:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adjacency List&lt;/strong>
&lt;ul>
&lt;li>All the nodes are stores in a hashmap. The key is the node and the value is an array of all the nodes that are connected to the key node.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Adjacency Matrix&lt;/strong>
&lt;ul>
&lt;li>A 2D array that stores the connections between nodes. The value at index &lt;code>(i,j)&lt;/code> is 1 if there is an edge between node &lt;code>i&lt;/code> and node &lt;code>j&lt;/code>.&lt;/li>
&lt;li>In case of undirected graphs, the value at index &lt;code>(i,j)&lt;/code> and &lt;code>(j,i)&lt;/code> need not be symmetrical.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;div class="alert alert-note">
&lt;div>
The &lt;em>adjacency matrix&lt;/em> is a good graph representation, when the graph is dense. On the other hand, the &lt;em>adjacency list&lt;/em> is a good representation when the graph is sparse.
&lt;/div>
&lt;/div>
&lt;p>&lt;strong>Key Ideas:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>The number of &lt;em>incoming&lt;/em> and &lt;em>outgoing&lt;/em> edges of a node is called &lt;em>indegree&lt;/em> and &lt;em>outdegree&lt;/em>, respectively.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;em>degree&lt;/em> of a node is the number of incoming and outgoing edges.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>A directed graph is acyclical if there are no cycles in the graph. That is, all the directed edges in the graph does not form a closed loop.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="i-adjacency-list">I. Adjacency List&lt;/h3>
&lt;p>&lt;strong>Time complexities&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Operation&lt;/th>
&lt;th>Worst-case Time complexity&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Add node (N)&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Add edge (E)&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Remove node (N)&lt;/td>
&lt;td>&lt;code>O(N+E)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Get adjacent nodes&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Check if node is adjacent&lt;/td>
&lt;td>&lt;code>O(n)&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Space complexity&lt;/strong>: &lt;code>O(N+E)&lt;/code>&lt;/p>
&lt;h3 id="ii-adjacency-matrix">II. Adjacency Matrix&lt;/h3>
&lt;p>&lt;strong>Time complexities&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Operation&lt;/th>
&lt;th>Worst-case Time complexity&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Add node (N)&lt;/td>
&lt;td>&lt;code>O(N^2)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Add edge (E)&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Remove node (N)&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Get adjacent nodes&lt;/td>
&lt;td>&lt;code>O(N)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Check if node is adjacent&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Space complexity&lt;/strong>: &lt;code>O(N^2)&lt;/code>&lt;/p>
&lt;h2 id="b-leetcode-problems">B. Leetcode problems&lt;/h2>
&lt;h3 id="133-clone-graph">133. Clone Graph&lt;/h3>
&lt;p>Given a reference of a node in a connected undirected graph.&lt;/p>
&lt;p>Return a deep copy (clone) of the graph.&lt;/p>
&lt;p>Each node in the graph contains a value (&lt;code>int&lt;/code>) and a list (&lt;code>List[Node]&lt;/code>) of its neighbors.&lt;/p>
&lt;pre>&lt;code class="language-python">
class Node:
val:int
neighbors: List[Node]
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Test case format:&lt;/strong>&lt;/p>
&lt;p>For simplicity, each node&amp;rsquo;s value is the same as the node&amp;rsquo;s index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is represented in the test case using an adjacency list.&lt;/p>
&lt;p>An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.&lt;/p>
&lt;p>The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsclone-graph">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/clone-graph/" srcset="
/media/leetcode/133_clone_graph_question_hu2384f8fafae20a11024102542cf24798_72478_4a3ead79ad3194bdd40c2f3cd35c6e61.webp 400w,
/media/leetcode/133_clone_graph_question_hu2384f8fafae20a11024102542cf24798_72478_ec343efc02ca7e4e310393795c92641e.webp 760w,
/media/leetcode/133_clone_graph_question_hu2384f8fafae20a11024102542cf24798_72478_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/133_clone_graph_question_hu2384f8fafae20a11024102542cf24798_72478_4a3ead79ad3194bdd40c2f3cd35c6e61.webp"
width="500px"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/clone-graph/">https://leetcode.com/problems/clone-graph/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;h5 id="key-ideas">Key Ideas&lt;/h5>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used&lt;/strong>: Depth-first search
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>Maintain a hashmap to track the clone of each node&lt;/li>
&lt;li>use a graph traversal algorithm to clone the graph
&lt;ul>
&lt;li>Pop a node from the queue/stack; check if the node has a clone in the hashmap; if not, create a clone and add it to the hashmap&lt;/li>
&lt;li>Iterate through neighbors and check if they have a copy and add it to the clone&amp;rsquo;s neighbors&lt;/li>
&lt;li>Maintain a visited set to avoid infinite loop&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Return the clone of the given node&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-4">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
&amp;quot;&amp;quot;&amp;quot;
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
&amp;quot;&amp;quot;&amp;quot;
class Solution:
def cloneGraph(self, node: 'Node') -&amp;gt; 'Node':
# 1. Have a hash map which tracks a new node for every old node
# 2. pop a node from the stack, check if there is a copy in map else, create a new one
# 3. start looping through neighbors and check if they have copy and add it to new node children
if node is None:
return None
old2new = {}
queue = [node]
visited = set()
while queue:
cur_node = queue.pop()
visited.add(cur_node)
if (cur_node in old2new) is False:
old2new[cur_node] = Node(cur_node.val)
new_node = old2new[cur_node]
for n in cur_node.neighbors:
if (n in old2new) is False:
old2new[n] = Node(n.val)
new_n = old2new[n]
new_node.neighbors.append(new_n)
if n not in visited:
queue.append(n)
visited.add(n)
return old2new[node]
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="994-rotting-oranges">994. Rotting Oranges&lt;/h3>
&lt;p>You are given an &lt;code>m x n&lt;/code> grid where each cell can have one of three values:&lt;/p>
&lt;ul>
&lt;li>0 representing an empty cell,&lt;/li>
&lt;li>1 representing a fresh orange, or&lt;/li>
&lt;li>2 representing a rotten orange.&lt;/li>
&lt;/ul>
&lt;p>Every minute, any fresh orange that is &lt;strong>4-directionally adjacent&lt;/strong> to a rotten orange becomes rotten.&lt;/p>
&lt;p>Return &lt;em>the minimum number of minutes that must elapse until no cell has a fresh orange.&lt;/em> If this is impossible, return -1.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsrotting-oranges">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/rotting-oranges/" srcset="
/media/leetcode/rotting_oranges_1_hu80ece0439f120d211a32693abd2dfdea_42586_6f5a7cdde7ef8fe094b790c447ad3f13.webp 400w,
/media/leetcode/rotting_oranges_1_hu80ece0439f120d211a32693abd2dfdea_42586_2b7a934f4fc0210b87f359fad0162712.webp 760w,
/media/leetcode/rotting_oranges_1_hu80ece0439f120d211a32693abd2dfdea_42586_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/rotting_oranges_1_hu80ece0439f120d211a32693abd2dfdea_42586_6f5a7cdde7ef8fe094b790c447ad3f13.webp"
width="760"
height="160"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/rotting-oranges/">https://leetcode.com/problems/rotting-oranges/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;h5 id="key-ideas-1">Key Ideas&lt;/h5>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used&lt;/strong>: Multi-source breadth-first search
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>
&lt;p>An easy way to iterate level by level is to use an inner loop to iterate &lt;code>k&lt;/code> number of times, where &lt;code>k&lt;/code> is length of the queue at the start of inner loop.
&lt;br/>&lt;br/>&lt;/p>
&lt;pre>&lt;code class="language-python">while queue:
q_len = len(queue)
for _ in range(q_len):
... # do something
&lt;/code>&lt;/pre>
&lt;p>This formulation can be used for &lt;em>multi-source BFS.&lt;/em>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Use a counter variable to track the number of fresh oranges&lt;/p>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-7">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">from collections import deque
from itertools import product
class Solution:
def orangesRotting(self, grid: List[List[int]]) -&amp;gt; int:
time_step = 0
fresh_oranges = 0
m,n = len(grid), len(grid[0])
DIRECTIONS = [(1,0), (0,1), (-1, 0), (0, -1)]
check_valid_coord = lambda x, y: x &amp;gt;=0 and x &amp;lt; m and y &amp;gt;= 0 and y &amp;lt; n
queue = deque([])
for i,j in product(range(m), range(n)):
if grid[i][j] == 2:
queue.append((i,j))
if grid[i][j] == 1:
fresh_oranges += 1
while queue and fresh_oranges &amp;gt; 0:
time_step += 1
q_len = len(queue)
for _ in range(q_len):
x,y = queue.popleft()
for dx, dy in DIRECTIONS:
xx,yy = x+dx, y+dy
if check_valid_coord(xx,yy) and grid[xx][yy] == 1:
grid[xx][yy] = 2
queue.append((xx,yy))
fresh_oranges -= 1
if fresh_oranges &amp;gt; 0:
return -1
return time_step
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong> &lt;code>O(m*n)&lt;/code>, where &lt;code>m&lt;/code> is the number of rows and &lt;code>n&lt;/code> is the number of columns. &lt;br>
&lt;strong>Space complexity:&lt;/strong> &lt;code>O(m*n)&lt;/code>, in worst case, the queue is filled with all the coordinates in the grid.&lt;/p>
&lt;h3 id="684-redundant-connection">684. Redundant Connection&lt;/h3>
&lt;p>In this problem, a tree is an undirected graph that is connected and has no cycles.&lt;/p>
&lt;p>You are given a graph that started as a tree with &lt;code>n&lt;/code> nodes labeled from 1 to n, with one additional edge added. The added edge has two &lt;strong>different&lt;/strong> vertices chosen from 1 to n, and was not an edge that already existed. The graph is represented as an array &lt;code>edges&lt;/code> of length n where &lt;code>edges[i] = [ai, bi]&lt;/code> indicates that there is an edge between nodes &lt;code>ai&lt;/code> and &lt;code>bi&lt;/code> in the graph.&lt;/p>
&lt;p>Return an edge that can be removed so that the resulting graph is a tree of &lt;code>n&lt;/code> nodes. If there are multiple answers, return the answer that occurs last in the input.&lt;/p>
&lt;p>Example 1:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsredundant-connection">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/redundant-connection/" srcset="
/media/leetcode/redundant_connection_1_huc16733ba96cab13b1f59f1c2a143b251_9741_b7c6df8ac18a3a259e9a6b69820de323.webp 400w,
/media/leetcode/redundant_connection_1_huc16733ba96cab13b1f59f1c2a143b251_9741_0904cb2eea5197509763004a9f49cb17.webp 760w,
/media/leetcode/redundant_connection_1_huc16733ba96cab13b1f59f1c2a143b251_9741_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/redundant_connection_1_huc16733ba96cab13b1f59f1c2a143b251_9741_b7c6df8ac18a3a259e9a6b69820de323.webp"
width="382"
height="222"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/redundant-connection/">https://leetcode.com/problems/redundant-connection/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;p>Answer: &lt;code>[1,4]&lt;/code>&lt;/p>
&lt;h4 id="key-ideas-2">Key Ideas&lt;/h4>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used&lt;/strong>: Breadth-first search
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>Represent the graph as an adjacency list&lt;/li>
&lt;li>Maintain a results list, which contains the edges that can be removed.&lt;/li>
&lt;li>Iterate through the edges&lt;/li>
&lt;li>If two nodes are already connected, add the edge to results list
&lt;ul>
&lt;li>else: connect the nodes with the edge&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>return the last element in the results list&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-10">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">from collections import defaultdict, deque
class Graph:
def __init__(self, N:int) -&amp;gt; None:
self.N = N
self.edges = defaultdict(list)
def connect(self, p:int, q:int) -&amp;gt; None:
self.edges[p].append(q)
self.edges[q].append(p)
def is_connected(self, p:int, q:int) -&amp;gt; bool:
if p in self.edges[q]:
return True
queue = deque([p])
visited = set()
while queue:
node = queue.popleft()
visited.add(node)
if node == q:
return True
for child in self.edges[node]:
if child not in visited:
queue.append(child)
visited.add(child)
return False
class Solution:
def findRedundantConnection(self, edges: List[List[int]]) -&amp;gt; List[int]:
n = len(edges)
g = Graph(n)
result = []
for edge in edges:
p = edge[0]
q = edge[1]
connected = g.is_connected(p,q)
if connected is False:
g.connect(p,q)
continue
result.append(edge)
return result[-1]
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong> &lt;code>O(n^2)&lt;/code>, &lt;br>
&lt;strong>Space complexity:&lt;/strong> &lt;code>O(n^2)&lt;/code>.&lt;/p>
&lt;h3 id="743-network-delay-time">743. Network Delay Time&lt;/h3>
&lt;p>You are given a network of n nodes, labeled from &lt;code>1&lt;/code> to &lt;code>n&lt;/code>. You are also given &lt;code>times&lt;/code>, a list of travel times as directed edges &lt;code>times[i] = (ui, vi, wi)&lt;/code>, where &lt;code>ui&lt;/code> is the source node, &lt;code>vi&lt;/code> is the target node, and &lt;code>wi&lt;/code> is the time it takes for a signal to travel from source to target.&lt;/p>
&lt;p>We will send a signal from a given node &lt;code>k&lt;/code>. Return the &lt;strong>minimum&lt;/strong> time it takes for all the &lt;code>n&lt;/code> nodes to receive the &lt;em>signal&lt;/em>. If it is impossible for all the &lt;code>n&lt;/code> nodes to receive the signal, return &lt;code>-1&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsnetwork-delay-time">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/network-delay-time/" srcset="
/media/leetcode/931_example_1_huce04d9b70d9e7578bd929ffb8f9dd290_7562_0f1e4ad1391d692cd169f614409d05d4.webp 400w,
/media/leetcode/931_example_1_huce04d9b70d9e7578bd929ffb8f9dd290_7562_bf9b384922157e7b6c9523e4955d00a3.webp 760w,
/media/leetcode/931_example_1_huce04d9b70d9e7578bd929ffb8f9dd290_7562_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/931_example_1_huce04d9b70d9e7578bd929ffb8f9dd290_7562_0f1e4ad1391d692cd169f614409d05d4.webp"
width="150px"
height="239"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/network-delay-time/">https://leetcode.com/problems/network-delay-time/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2 &lt;br>
&lt;strong>Output:&lt;/strong> 2&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-3">Key Ideas&lt;/h4>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used&lt;/strong>: Djikstra algorithm
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>Use a &lt;code>min-heap&lt;/code> to store the nodes and their corresponding time&lt;/li>
&lt;li>When iterating through the edges, add the time to the current time and push it to the heap&lt;/li>
&lt;li>Use a min_time variable to track the minimum time taken to reach all the node&lt;/li>
&lt;li>Finally, check if the all the nodes were visited
&lt;ul>
&lt;li>If not, return -1&lt;/li>
&lt;li>Else, return the min_time&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-13">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
from collections import defaultdict
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -&amp;gt; int:
graph = defaultdict(list)
for u,v,w in times:
graph[u].append((v,w))
queue = [(0, k)] # time, node
visited = set()
min_time = 0
while queue:
time, node = heapq.heappop(queue)
if node in visited:
continue
visited.add(node)
min_time = max(min_time, time)
for child_node, child_time in graph[node]:
if child_node not in visited:
heapq.heappush(queue, (time+child_time, child_node))
return min_time if len(visited) == n else -1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="1584-min-cost-to-connect-all-points">1584. Min Cost to Connect All Points&lt;/h3>
&lt;p>You are given an array &lt;code>points&lt;/code> representing integer coordinates of some points on a 2D-plane, where &lt;code>points[i] = [xi, yi]&lt;/code>.&lt;/p>
&lt;p>The cost of connecting two points &lt;code>[xi, yi]&lt;/code> and &lt;code>[xj, yj]&lt;/code> is the &lt;strong>manhattan distance&lt;/strong> between them: &lt;code>|xi - xj| + |yi - yj|&lt;/code>, where &lt;code>|val|&lt;/code> denotes the absolute value of &lt;code>val&lt;/code>.&lt;/p>
&lt;p>Return the minimum &lt;em>cost&lt;/em> to make all points connected. All points are connected if there is &lt;strong>exactly one&lt;/strong> simple path between any two points.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsmin-cost-to-connect-all-points">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/min-cost-to-connect-all-points/" srcset="
/media/leetcode/mst_1584_hucf5db536195287a686c58522d4c52f9d_7012_c74dceab9a8c85007fe6258875ac2bb9.webp 400w,
/media/leetcode/mst_1584_hucf5db536195287a686c58522d4c52f9d_7012_b91ede1baeb3faef0c2f48b3f18226d7.webp 760w,
/media/leetcode/mst_1584_hucf5db536195287a686c58522d4c52f9d_7012_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/mst_1584_hucf5db536195287a686c58522d4c52f9d_7012_c74dceab9a8c85007fe6258875ac2bb9.webp"
width="200px"
height="268"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/min-cost-to-connect-all-points/">https://leetcode.com/problems/min-cost-to-connect-all-points/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> points = [[0,0],[2,2],[3,10],[5,2],[7,0]] &lt;br>
&lt;strong>Output:&lt;/strong> 20&lt;/p>
&lt;/blockquote>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsmin-cost-to-connect-all-points">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/min-cost-to-connect-all-points/" srcset="
/media/leetcode/mst_1584a_hu761bf62ddfc9a28878ab99c3b5838601_10326_2a9cce06f1c6cfe9b00d0e5500af7b16.webp 400w,
/media/leetcode/mst_1584a_hu761bf62ddfc9a28878ab99c3b5838601_10326_752d669790a9dfb1750babb10eb52731.webp 760w,
/media/leetcode/mst_1584a_hu761bf62ddfc9a28878ab99c3b5838601_10326_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/mst_1584a_hu761bf62ddfc9a28878ab99c3b5838601_10326_2a9cce06f1c6cfe9b00d0e5500af7b16.webp"
width="200px"
height="268"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/min-cost-to-connect-all-points/">https://leetcode.com/problems/min-cost-to-connect-all-points/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.&lt;/p>
&lt;/blockquote>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used:&lt;/strong> Prim&amp;rsquo;s Algorithm
&lt;/div>
&lt;/div>
&lt;h4 id="key-ideas-4">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>&lt;strong>Goal:&lt;/strong> &lt;em>Path which connects all the points at the minimum cost&lt;/em>&lt;/li>
&lt;li>Use a min-heap to store the cost for each node combination that can be explored&lt;/li>
&lt;li>Use a set to track the visited nodes&lt;/li>
&lt;li>Iterate till the visited set is equal to the number of nodes&lt;/li>
&lt;li>At every pop, check if the node is already visited
&lt;ul>
&lt;li>If yes, skip the node and continue&lt;/li>
&lt;li>Else, add the node to the visited set&lt;/li>
&lt;li>Add the cost of the node to the path_cost variable&lt;/li>
&lt;li>explore the children&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-17">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
from collections import defaultdict
import heapq
class Solution:
def minCostConnectPoints(self, points: List[List[int]]) -&amp;gt; int:
mhat_dist = lambda x1, y1, x2, y2: abs(x1 - x2) + abs(y1 - y2)
graph = defaultdict(list)
for i, (x1,y1) in enumerate(points):
for j in range(i+1, len(points)):
x2, y2 = points[j]
dist = mhat_dist(x1,y1, x2, y2)
graph[i].append((dist, j))
graph[j].append((dist, i))
queue = [(0,0)]
visited = set()
min_cost = 0
while len(visited) &amp;lt; len(points):
cost, pt = heapq.heappop(queue)
if pt in visited:
continue
visited.add(pt)
min_cost += cost
for w, cpt in graph[pt]:
if cpt not in visited:
heapq.heappush(queue, (w, cpt))
return min_cost
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="778-swim-in-rising-water">778. Swim in Rising Water&lt;/h3>
&lt;p>You are given an &lt;code>n x n&lt;/code> integer matrix &lt;code>grid&lt;/code> where each value &lt;code>grid[i][j]&lt;/code> represents the elevation at that point &lt;code>(i, j)&lt;/code>.&lt;/p>
&lt;p>The rain starts to fall. At time &lt;code>t&lt;/code>, the depth of the water everywhere is &lt;code>t&lt;/code>. You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most &lt;code>t&lt;/code>. You can swim infinite distances in zero time. Of course, you must stay within the boundaries of the grid during your swim.&lt;/p>
&lt;p>Return the least time until you can reach the bottom right square &lt;code>(n - 1, n - 1)&lt;/code> if you start at the top left square &lt;code>(0, 0)&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsswim-in-rising-water">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/swim-in-rising-water/" srcset="
/media/leetcode/swim2-grid-1_hue5112e37e26bd2f3978092a07582d35e_22389_ffa9d1ea6a551ba5ec51813cd674898e.webp 400w,
/media/leetcode/swim2-grid-1_hue5112e37e26bd2f3978092a07582d35e_22389_40fa2c9acd95f3a8165dd27e6faa510d.webp 760w,
/media/leetcode/swim2-grid-1_hue5112e37e26bd2f3978092a07582d35e_22389_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/swim2-grid-1_hue5112e37e26bd2f3978092a07582d35e_22389_ffa9d1ea6a551ba5ec51813cd674898e.webp"
width="200px"
height="405"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/swim-in-rising-water/">https://leetcode.com/problems/swim-in-rising-water/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]] &lt;br>
&lt;strong>Output:&lt;/strong> 16 &lt;br>
&lt;strong>Explanation:&lt;/strong> The final route is shown. &lt;br>
We need to wait until time 16 so that (0, 0) and (4, 4) are connected.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-5">Key Ideas&lt;/h4>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used:&lt;/strong> Dijkstra&amp;rsquo;s Algorithm
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>Use a min-heap to store the nodes and their corresponding time
&lt;ul>
&lt;li>At any moment, we can only move to the node with elevation of at most the current time&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Traverse till the botton right node is reached and return the time&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-20">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class Solution:
def swimInWater(self, grid: List[List[int]]) -&amp;gt; int:
# (t, (x,y))
# Maintain a min-heap to store the frontier nodes
# - Pop from the min-heap
# - choosing the node which has less wait time compared
n = len(grid)
DIRECTIONS = [(0,1), (1,0), (0,-1), (-1,0)]
queue = [(grid[0][0], (0,0))]
visited = set()
visited.add((0,0))
check_boundaries = lambda x, y: x &amp;gt;= 0 and x &amp;lt; n and y &amp;gt;= 0 and y &amp;lt; n
while queue:
t, (x,y) = heapq.heappop(queue)
if x == n-1 and y == n-1:
break
for dx,dy in DIRECTIONS:
xx = x+dx
yy = y+dy
if check_boundaries(xx,yy) and (xx,yy) not in visited:
heapq.heappush(queue, (max(t, grid[xx][yy]), (xx,yy)))
visited.add((xx,yy))
return t
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong> &lt;code>O(nlogn)&lt;/code>, &lt;br>
&lt;strong>Space complexity:&lt;/strong> &lt;code>O(n^2)&lt;/code>.&lt;/p>
&lt;h3 id="787-cheapest-flights-within-k-stops">787. Cheapest Flights Within K Stops&lt;/h3>
&lt;p>There are &lt;code>n&lt;/code> cities connected by some number of flights. You are given an array &lt;code>flights&lt;/code> where &lt;code>flights[i] = [fromi, toi, pricei]&lt;/code> indicates that there is a flight from city &lt;code>fromi&lt;/code> to city &lt;code>toi&lt;/code> with cost &lt;code>pricei&lt;/code>.&lt;/p>
&lt;p>You are also given three integers &lt;code>src&lt;/code>, &lt;code>dst&lt;/code>, and &lt;code>k&lt;/code>, return &lt;strong>the cheapest price&lt;/strong> from &lt;code>src&lt;/code> to &lt;code>dst&lt;/code> with at most &lt;code>k&lt;/code> stops. If there is no such route, return &lt;code>-1&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemscheapest-flights-within-k-stops">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/cheapest-flights-within-k-stops/" srcset="
/media/leetcode/cheapest-flights-within-k-stops-3drawio_hu50c9700c095b339c203b9be9ef1216af_23339_118c7b6528985a4ca90b1b16337257d7.webp 400w,
/media/leetcode/cheapest-flights-within-k-stops-3drawio_hu50c9700c095b339c203b9be9ef1216af_23339_ad7c39400ca728b4c14181dd92b6b6e1.webp 760w,
/media/leetcode/cheapest-flights-within-k-stops-3drawio_hu50c9700c095b339c203b9be9ef1216af_23339_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/cheapest-flights-within-k-stops-3drawio_hu50c9700c095b339c203b9be9ef1216af_23339_118c7b6528985a4ca90b1b16337257d7.webp"
width="300px"
height="392"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/cheapest-flights-within-k-stops/">https://leetcode.com/problems/cheapest-flights-within-k-stops/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1 &lt;br>
&lt;strong>Output:&lt;/strong> 700 &lt;br>
&lt;br>
&lt;strong>Explanation:&lt;/strong>
The graph is shown above.
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-6">Key Ideas&lt;/h4>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Algorithm used:&lt;/strong> Multisource BFS
&lt;/div>
&lt;/div>
&lt;ul>
&lt;li>Use a multisource BFS to search layer by layer&lt;/li>
&lt;li>Maintain a visited array to store the minimum cost to reach a node
&lt;ul>
&lt;li>If the cost is greater than the cost in visited, then skip the node&lt;/li>
&lt;li>Else update visited and continue the search&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-23">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
from collections import deque, defaultdict
class Solution:
def findCheapestPrice(self,
n: int, flights: List[List[int]], src: int, dst: int, K: int) -&amp;gt; int:
graph = defaultdict(dict)
for p, q, c in flights:
graph[p][q] = c
minCost = float(&amp;quot;inf&amp;quot;)
queue = deque([(0, src, K+1)])
visited = [float(&amp;quot;inf&amp;quot;)]*n
visited[src] = 0
while queue:
m = len(queue)
for _ in range(m):
cost, city, k = queue.popleft()
if k &amp;lt; 0 or cost &amp;gt; visited[city]:
continue
if city == dst:
minCost = min(minCost, cost)
visited[city] = cost
for adjcity, price in graph[city].items():
queue.append((price+cost, adjcity, k-1))
if minCost == float(&amp;quot;inf&amp;quot;):
return -1
return minCost
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="127-word-ladder">127. Word Ladder&lt;/h3>
&lt;p>A transformation sequence from word &lt;code>beginWord&lt;/code> to word &lt;code>endWord&lt;/code> using a dictionary &lt;code>wordList&lt;/code> is a sequence of words &lt;code>beginWord -&amp;gt; s1 -&amp;gt; s2 -&amp;gt; ... -&amp;gt; sk&lt;/code> such that:&lt;/p>
&lt;ul>
&lt;li>Every adjacent pair of words differs by a single letter.&lt;/li>
&lt;li>Every &lt;code>si&lt;/code> for &lt;code>1 &amp;lt;= i &amp;lt;= k&lt;/code> is in &lt;code>wordList&lt;/code>. Note that &lt;code>beginWord&lt;/code> does not need to be in &lt;code>wordList&lt;/code>.&lt;/li>
&lt;li>&lt;code>sk == endWord&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Given two words, &lt;code>beginWord&lt;/code> and endWord, and a dictionary wordList, return the &lt;strong>number of words&lt;/strong> in the &lt;strong>shortest transformation sequence&lt;/strong> from &lt;code>beginWord&lt;/code> to &lt;code>endWord&lt;/code>, or &lt;code>0&lt;/code> &lt;em>if no such sequence exists.&lt;/em>&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> beginWord = &amp;ldquo;hit&amp;rdquo;, endWord = &amp;ldquo;cog&amp;rdquo;, wordList = [&amp;ldquo;hot&amp;rdquo;,&amp;ldquo;dot&amp;rdquo;,&amp;ldquo;dog&amp;rdquo;,&amp;ldquo;lot&amp;rdquo;,&amp;ldquo;log&amp;rdquo;,&amp;ldquo;cog&amp;rdquo;] &lt;br>
&lt;strong>Output:&lt;/strong> 5 &lt;br>
&lt;strong>Explanation:&lt;/strong> As one shortest transformation is &amp;ldquo;hit&amp;rdquo; -&amp;gt; &amp;ldquo;hot&amp;rdquo; -&amp;gt; &amp;ldquo;dot&amp;rdquo; -&amp;gt; &amp;ldquo;dog&amp;rdquo; -&amp;gt; &amp;ldquo;cog&amp;rdquo;, return its length 5.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-7">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@Idea&lt;/code> The entire problem can be thought of as a graph problem
&lt;ul>
&lt;li>The nodes are the words in the wordList&lt;/li>
&lt;li>The edges are the words which differ by a single letter&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>@Idea&lt;/code> Use a BFS to find the shortest path from beginWord to endWord&lt;/li>
&lt;li>Create a pattern map; &lt;code>pattern&lt;/code> -&amp;gt; &lt;code>List[word]&lt;/code>&lt;/li>
&lt;li>Perform &lt;strong>multi-source BFS&lt;/strong> to keep track of the number of transformations
&lt;ul>
&lt;li>The number of transformations is the layer at which &lt;code>endWord&lt;/code> is located from &lt;code>beginWord&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-24">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -&amp;gt; int:
&amp;quot;&amp;quot;&amp;quot;
@Idea: BFS on the graph, when the endWord is reached return
the level at which it was located.
Algorithm:
1. Create the pattern mapping
2. Perform multi-source BFS from the beginWord
&amp;quot;&amp;quot;&amp;quot;
if endWord not in wordList:
return 0
wordList.append(beginWord)
# pattern -&amp;gt; List of all words of the pattern
patternMap = collections.defaultdict(list)
n = len(beginWord)
for word in wordList:
for i in range(n):
pattern = word[:i]+&amp;quot;*&amp;quot;+word[i+1:]
patternMap[pattern].append(word)
transforms = 1
queue = collections.deque([beginWord])
visited = set([beginWord])
while queue:
m = len(queue)
for _ in range(m):
node = queue.popleft()
if node == endWord:
return transforms
for i in range(n):
pattern = node[:i]+&amp;quot;*&amp;quot;+node[i+1:]
for neigh in patternMap[pattern]:
if neigh not in visited:
queue.append(neigh)
visited.add(neigh)
transforms += 1
return 0
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>4. Heaps / Priority Queues</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/4.-heaps/</link><pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/4.-heaps/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-general-introduction">A. General Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-leetcode-problems">B. Leetcode Problems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#1046-last-stone-weight">1046. Last Stone Weight&lt;/a>&lt;/li>
&lt;li>&lt;a href="#703-kth-largest-element-in-a-stream">703. Kth Largest Element in a Stream&lt;/a>&lt;/li>
&lt;li>&lt;a href="#973-k-closest-points-to-origin">973. K Closest Points to Origin&lt;/a>&lt;/li>
&lt;li>&lt;a href="#355-design-twitter">355. Design Twitter&lt;/a>&lt;/li>
&lt;li>&lt;a href="#621-task-scheduler">621. Task Scheduler&lt;/a>&lt;/li>
&lt;li>&lt;a href="#295-find-median-from-data-stream">295. Find Median from Data Stream&lt;/a>&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;p>&lt;strong>Heaps&lt;/strong> are concrete data structures, whereas &lt;em>priority queues&lt;/em> are abstract data structures. An abstract data structure determines the interface, while a concrete data structure defines the implementation.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p>
&lt;figure id="figure-httpsenwikipediaorgwikiheap_28data_structure29">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="https://en.wikipedia.org/wiki/Heap_%28data_structure%29" srcset="
/media/leetcode/Max-Heap-new_hu106933959d61350a071dbc00f3aae2f0_78288_87b8461aa272cd9d9f581287b559bca1.webp 400w,
/media/leetcode/Max-Heap-new_hu106933959d61350a071dbc00f3aae2f0_78288_34cb83b9fad575c7d0f29fb3cc0de7af.webp 760w,
/media/leetcode/Max-Heap-new_hu106933959d61350a071dbc00f3aae2f0_78288_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/Max-Heap-new_hu106933959d61350a071dbc00f3aae2f0_78288_87b8461aa272cd9d9f581287b559bca1.webp"
width="300px"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
&lt;a href="https://en.wikipedia.org/wiki/Heap_%28data_structure%29">https://en.wikipedia.org/wiki/Heap_%28data_structure%29&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;p>In a &lt;em>heap tree&lt;/em>, the value in a node is always smaller than both of its children. This is called the &lt;strong>heap property&lt;/strong>.&lt;/p>
&lt;p>Generally, heaps can be of two types&lt;/p>
&lt;ol>
&lt;li>Min-heap: The smallest element is always at the root of the tree.&lt;/li>
&lt;li>Max-heap: The largest element is always at the root of the tree.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Time Complexity&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Operation&lt;/th>
&lt;th>Worst-case Time complexity&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Build a binary heap (heapify)&lt;/td>
&lt;td>&lt;code>O(n)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Insert an element&lt;/td>
&lt;td>&lt;code>O(log n)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Delete an element&lt;/td>
&lt;td>&lt;code>O(log n)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Find the max/min&lt;/td>
&lt;td>&lt;code>O(1)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Find the kth largest element (max-heap)&lt;/td>
&lt;td>&lt;code>O(k*log(n))&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Heap sort&lt;/td>
&lt;td>&lt;code>O(n*log(n))&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="b-leetcode-problems">B. Leetcode Problems&lt;/h2>
&lt;h3 id="1046-last-stone-weight">1046. Last Stone Weight&lt;/h3>
&lt;p>You are given an array of integers &lt;code>stones&lt;/code> where &lt;code>stones[i]&lt;/code> is the weight of the &lt;code>ith&lt;/code> stone.&lt;/p>
&lt;p>We are playing a game with the stones. On each turn, we choose the &lt;strong>heaviest two stones&lt;/strong> and smash them together. Suppose the heaviest two stones have weights &lt;code>x&lt;/code> and &lt;code>y&lt;/code> with &lt;code>x &amp;lt;= y&lt;/code>. The result of this smash is:&lt;/p>
&lt;p>If &lt;code>x == y&lt;/code>, both stones are destroyed, and
If &lt;code>x != y&lt;/code>, the stone of weight &lt;code>x&lt;/code> is destroyed, and the stone of weight &lt;code>y&lt;/code> has new weight &lt;code>y - x&lt;/code>.
At the end of the game, there is at most one stone left.&lt;/p>
&lt;p>Return the weight of the last remaining stone. If there are no stones left, return &lt;code>0&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input&lt;/strong>: stones = [2,7,4,1,8,1] &lt;br>
&lt;strong>Output&lt;/strong>: 1 &lt;br>
&lt;strong>Explanation&lt;/strong>: &lt;br>
We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1], &lt;br>
we combine 2 and 4 to get 2 so the array converts to [2,1,1,1], &lt;br>
we combine 2 and 1 to get 1 so the array converts to [1,1,1], &lt;br>
we combine 1 and 1 to get 0 so the array converts to [1] then that&amp;rsquo;s the value of the last stone.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>the default implementation in &lt;code>heapq&lt;/code> is min-heap
&lt;ul>
&lt;li>so the values are made negative to make them max-heap&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>When pushing and popping to the heap, the value is negated&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class Solution:
def lastStoneWeight(self, stones: List[int]) -&amp;gt; int:
stones = [-1*stone for stone in stones]
heapq.heapify(stones)
while len(stones) &amp;gt; 1:
s1 = -1 * heapq.heappop(stones)
s2 = -1 * heapq.heappop(stones) # s2 &amp;lt;= s1
if s1 != s2:
new_stone = -1*(s1 - s2)
heapq.heappush(stones, new_stone)
stones.append(0)
return abs(stones[0])
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time Complexity:&lt;/strong> &lt;code>O(nlog(n))&lt;/code>&lt;/p>
&lt;h3 id="703-kth-largest-element-in-a-stream">703. Kth Largest Element in a Stream&lt;/h3>
&lt;p>Design a class to find the &lt;code>kth&lt;/code> largest element in a stream. Note that it is the &lt;code>kth&lt;/code> largest element in the sorted order, not the &lt;code>kth&lt;/code> distinct element.&lt;/p>
&lt;p>Implement &lt;code>KthLargest&lt;/code> class:&lt;/p>
&lt;ul>
&lt;li>&lt;code>KthLargest(int k, int[] nums)&lt;/code> Initializes the object with the integer &lt;code>k&lt;/code> and the stream of integers &lt;code>nums&lt;/code>.&lt;/li>
&lt;li>&lt;code>int add(int val)&lt;/code> Appends the integer val to the stream and returns the element representing the &lt;code>kth&lt;/code> largest element in the stream.&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> &lt;br>
[&amp;ldquo;KthLargest&amp;rdquo;, &amp;ldquo;add&amp;rdquo;, &amp;ldquo;add&amp;rdquo;, &amp;ldquo;add&amp;rdquo;, &amp;ldquo;add&amp;rdquo;, &amp;ldquo;add&amp;rdquo;] &lt;br>
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]] &lt;br>
&lt;br>
&lt;strong>Output:&lt;/strong> &lt;br>
[null, 4, 5, 5, 8, 8] &lt;br>
&lt;br>
&lt;strong>Explanation:&lt;/strong> &lt;br>
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]); &lt;br>
kthLargest.add(3); // return 4 &lt;br>
kthLargest.add(5); // return 5 &lt;br>
kthLargest.add(10); // return 5 &lt;br>
kthLargest.add(9); // return 8 &lt;br>
kthLargest.add(4); // return 8&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>Always maintain the list size of &lt;code>k&lt;/code>
&lt;ul>
&lt;li>use heappop to pop the smallest &lt;code>(n-k)&lt;/code> elements&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>when inserting, pop the last element if the size is greater than &lt;code>k&lt;/code>&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-3">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class KthLargest:
def __init__(self, k: int, nums: List[int]):
self.nums = nums
self.k = k
heapq.heapify(self.nums) # O(n)
while len(self.nums) &amp;gt; self.k:
heapq.heappop(self.nums)
def add(self, val: int) -&amp;gt; int:
heapq.heappush(self.nums, val)
if len(self.nums) &amp;gt; self.k:
heapq.heappop(self.nums)
return self.nums[0] # using a min-heap
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>The constructor&amp;rsquo;s time complexity would be &lt;code>O(nlog(n) + (n-k)log(n))&lt;/code> -&amp;gt; &lt;code>O(nlog(n))&lt;/code>&lt;/li>
&lt;li>The add&amp;rsquo;s time complexity would be &lt;code>O(log(n))&lt;/code>, as the heap is always maintained at size &lt;code>k&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="973-k-closest-points-to-origin">973. K Closest Points to Origin&lt;/h3>
&lt;p>Given an array of &lt;code>points&lt;/code> where &lt;code>points[i] = [xi, yi]&lt;/code> represents a point on the X-Y plane and an integer &lt;code>k&lt;/code>, return the &lt;code>k&lt;/code> closest points to the origin &lt;code>(0, 0)&lt;/code>.&lt;/p>
&lt;p>The distance between two points on the X-Y plane is the Euclidean distance (i.e., &lt;code>√(x1 - x2)^2 + (y1 - y2)^2)&lt;/code>.&lt;/p>
&lt;p>You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-httpsleetcodecomproblemsk-closest-points-to-origin">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="https://leetcode.com/problems/k-closest-points-to-origin/" srcset="
/media/leetcode/closestplane1_huf5b749c97049abeae3d2d1b70c7807ae_17372_dcbe3c3b2882886fccd87e79b8ed74df.webp 400w,
/media/leetcode/closestplane1_huf5b749c97049abeae3d2d1b70c7807ae_17372_3eac24e9c1b4f335aa8de4c7213705d5.webp 760w,
/media/leetcode/closestplane1_huf5b749c97049abeae3d2d1b70c7807ae_17372_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/closestplane1_huf5b749c97049abeae3d2d1b70c7807ae_17372_dcbe3c3b2882886fccd87e79b8ed74df.webp"
width="300px"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
&lt;a href="https://leetcode.com/problems/k-closest-points-to-origin/">https://leetcode.com/problems/k-closest-points-to-origin/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> points = [[1,3],[-2,2]], k = 1 &lt;br>
&lt;strong>Output:&lt;/strong> [[-2,2]] &lt;br>
&lt;strong>Explanation:&lt;/strong> &lt;br>
The distance between (1, 3) and the origin is sqrt(10). &lt;br>
The distance between (-2, 2) and the origin is sqrt(8). &lt;br>
Since the distance between (-2, 2) and the origin is less than the distance between (1, 3) and the origin, (-2, 2) is closer to the origin.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-2">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>compute the distance of each point to the origin and store it in a list&lt;/li>
&lt;li>To get the k-nearest points, I tried two different methods and both seem to work
&lt;ol>
&lt;li>Method 1: Heaps
&lt;ul>
&lt;li>Use a min-heap to store the k-nearest points&lt;/li>
&lt;li>pop &lt;code>k&lt;/code> elements from the heap and return the points&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Method 2: Sort
&lt;ul>
&lt;li>Sort the list of distances and return the first &lt;code>k&lt;/code> elements&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-5">
&lt;summary>Code - Heap method&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class Solution:
def kClosest(self, points: List[List[int]], k: int) -&amp;gt; List[List[int]]:
# 1. Compute the euclidean distance from the origin
# 2. heap push all points -&amp;gt; nlogn
# 3. pop `k` elements from the heap -&amp;gt; klogn
distances = []
compute_distance = lambda x,y: (x**2 + y**2)**(0.5)
for x,y in points:
dist = compute_distance(x,y)
heapq.heappush((dist, [x,y]))
k_nearest = []
for _ in range(k):
_, pt = heapq.heappop(distances)
k_nearest.append(pt)
return k_nearest
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong> &lt;code>O((n+k)log(n))&lt;/code>&lt;/p>
&lt;details class="spoiler " id="spoiler-6">
&lt;summary>Code - Sort method&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">import heapq
class Solution:
def kClosest(self, points: List[List[int]], k: int) -&amp;gt; List[List[int]]:
distances = []
compute_distance = lambda x,y: (x**2 + y**2)**(0.5)
for x,y in points:
dist = compute_distance(x,y)
distances.append((dist, [x, y]))
distances = sorted(distances, key=lambda x: x[0]) # nlogn
k_nearest = []
for i in range(k): # k
_, pt = distances[i]
k_nearest.append(pt)
return k_nearest
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Time complexity:&lt;/strong> &lt;code>O(nlog(n))&lt;/code>&lt;/p>
&lt;h3 id="355-design-twitter">355. Design Twitter&lt;/h3>
&lt;p>Design a simplified version of Twitter where users can post tweets, follow/unfollow another user, and is able to see the &lt;code>10&lt;/code> most recent tweets in the user&amp;rsquo;s news feed.&lt;/p>
&lt;p>Implement the &lt;code>Twitter&lt;/code> class:&lt;/p>
&lt;ul>
&lt;li>&lt;code>Twitter()&lt;/code> Initializes your twitter object.&lt;/li>
&lt;li>&lt;code>void postTweet(int userId, int tweetId)&lt;/code> Composes a new tweet with ID &lt;code>tweetId&lt;/code> by the user userId. Each call to this function will be made with a unique &lt;code>tweetId&lt;/code>.&lt;/li>
&lt;li>&lt;code>List&amp;lt;Integer&amp;gt; getNewsFeed(int userId)&lt;/code> Retrieves the 10 most recent tweet IDs in the user&amp;rsquo;s news feed. Each item in the news feed must be posted by users who the user followed or by the user themself. Tweets must be &lt;strong>ordered from most recent to least recent.&lt;/strong>&lt;/li>
&lt;li>&lt;code>void follow(int followerId, int followeeId)&lt;/code> The user with ID &lt;code>followerId&lt;/code> started following the user with ID &lt;code>followeeId&lt;/code>.&lt;/li>
&lt;li>&lt;code>void unfollow(int followerId, int followeeId)&lt;/code> The user with ID &lt;code>followerId&lt;/code> started unfollowing the user with ID &lt;code>followeeId&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input&lt;/strong> &amp;gt; [&amp;ldquo;Twitter&amp;rdquo;, &amp;ldquo;postTweet&amp;rdquo;, &amp;ldquo;getNewsFeed&amp;rdquo;, &amp;ldquo;follow&amp;rdquo;, &amp;ldquo;postTweet&amp;rdquo;, &amp;ldquo;getNewsFeed&amp;rdquo;, &amp;ldquo;unfollow&amp;rdquo;, &amp;ldquo;getNewsFeed&amp;rdquo;] &lt;br>
[[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]] &lt;br>
&lt;br>
&lt;strong>Output&lt;/strong>
[null, null, [5], null, null, [6, 5], null, [5]] &lt;br>
&lt;details class="spoiler " id="spoiler-7">
&lt;summary>&lt;strong>Explanation&lt;/strong>&lt;/summary>
&lt;p>&lt;blockquote>
&lt;p>Twitter twitter = new Twitter(); &lt;br>
twitter.postTweet(1, 5); &lt;br>
// User 1 posts a new tweet (id = 5).
twitter.getNewsFeed(1); // User 1&amp;rsquo;s news feed should return a list with 1 tweet id -&amp;gt; [5]. return [5] &lt;br>
twitter.follow(1, 2); // User 1 follows user 2. &lt;br>
twitter.postTweet(2, 6); // User 2 posts a new tweet (id = 6). &lt;br>
twitter.getNewsFeed(1); // User 1&amp;rsquo;s news feed should return a list with 2 tweet ids -&amp;gt; [6, 5]. Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5. &lt;br>
twitter.unfollow(1, 2); // User 1 unfollows user 2. &lt;br>
twitter.getNewsFeed(1); // User 1&amp;rsquo;s news feed should return a list with 1 tweet id -&amp;gt; [5], since user 1 is no longer following user 2.&lt;/p>
&lt;/blockquote>
&lt;/p>
&lt;/details>&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-3">Key Ideas:&lt;/h4>
&lt;p>&lt;em>The tricky part of the problem was the use of multiple data structures for the problem.&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Use a &lt;code>hashmap&lt;/code> to store the tweets tweeted by each userId&lt;/li>
&lt;li>Use a &lt;code>hashmap&lt;/code> to store the users who are following each userId&lt;/li>
&lt;li>when a userId posts a tweet, add the tweet as a &lt;code>tuple&lt;/code> to the hashmap with a &lt;code>negative priority value&lt;/code>.&lt;/li>
&lt;li>To generate a feed, collate all the tweets from the users who are following the userId
&lt;ul>
&lt;li>Build a heap from the list of tweets; which takes &lt;code>O(n)&lt;/code>&lt;/li>
&lt;li>Pop the top &lt;code>10&lt;/code> elements from the heap and return the list of tweet ids; which takes &lt;code>O(10*logn)&lt;/code> $\approx$ &lt;code>O(logn)&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-8">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
from collections import defaultdict
class Twitter:
def __init__(self):
self.usersConn = defaultdict(list)
self.usersTweets = defaultdict(list)
self.tweet_pr = 0
def postTweet(self, userId: int, tweetId: int) -&amp;gt; None:
self.tweet_pr -= 1
self.usersTweets[userId].append((self.tweet_pr, tweetId))
def getNewsFeed(self, userId: int) -&amp;gt; List[int]:
if userId not in self.usersTweets and userId not in self.usersConn:
return []
feed = []
tweets = self.usersTweets[userId].copy()
for friend in self.usersConn[userId]:
tweets.extend(self.usersTweets[friend])
heapq.heapify(tweets)
while len(feed) &amp;lt; 10 and tweets:
obj = heapq.heappop(tweets)
_, tweetId = obj
feed.append(tweetId)
return feed
def follow(self, followerId: int, followeeId: int) -&amp;gt; None:
if followeeId not in self.usersConn[followerId]:
self.usersConn[followerId].append(followeeId) # O(1)
def unfollow(self, followerId: int, followeeId: int) -&amp;gt; None:
if followeeId in self.usersConn[followerId]:
self.usersConn[followerId].remove(followeeId) # O(n)
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="621-task-scheduler">621. Task Scheduler&lt;/h3>
&lt;p>Given a characters array &lt;code>tasks&lt;/code>, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks could be done in any order. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle.&lt;/p>
&lt;p>However, there is a non-negative integer &lt;code>n&lt;/code> that represents the cooldown period between two &lt;strong>same tasks&lt;/strong> (the same letter in the array), that is that there must be at least &lt;code>n&lt;/code> units of time between any two same tasks.&lt;/p>
&lt;p>Return &lt;em>the least number of units of times that the CPU will take to finish all the given tasks.&lt;/em>&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input&lt;/strong>: tasks = [&amp;ldquo;A&amp;rdquo;,&amp;ldquo;A&amp;rdquo;,&amp;ldquo;A&amp;rdquo;,&amp;ldquo;B&amp;rdquo;,&amp;ldquo;B&amp;rdquo;,&amp;ldquo;B&amp;rdquo;], n = 2 &lt;br>
&lt;strong>Output&lt;/strong>: 8 &lt;br>
&lt;strong>Explanation&lt;/strong>: &lt;br>
A -&amp;gt; B -&amp;gt; idle -&amp;gt; A -&amp;gt; B -&amp;gt; idle -&amp;gt; A -&amp;gt; B &lt;br>
There is at least 2 units of time between any two same tasks.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-4">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>use a max-heap to store the tasks&amp;rsquo;s counter&lt;/li>
&lt;li>have a while loop to simulate time
&lt;ul>
&lt;li>pop from the heap, and reduce the counter
&lt;ul>
&lt;li>add to the queue with the time at which it can be popped, with the counter&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>if the first element in the queue&amp;rsquo;s time is same as current time
&lt;ul>
&lt;li>pop the element and add it to the heap if the counter is non-zero positive&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>update the time&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-9">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
from collections import deque, Counter
import heapq
class Solution:
def leastInterval(self, tasks: List[str], n: int) -&amp;gt; int:
time = 0
queue = deque([])
max_heap = [-v for _, v in Counter(tasks).items()]
heapq.heapify(max_heap)
while queue or max_heap:
if max_heap:
val = heapq.heappop(max_heap)
val += 1
if val &amp;lt; 0:
queue.append((time+n, val))
if queue and queue[0][0] == time:
_, val = queue.popleft()
heapq.heappush(max_heap, val)
time += 1
return time
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="295-find-median-from-data-stream">295. Find Median from Data Stream&lt;/h3>
&lt;div class="alert alert-note">
&lt;div>
&lt;strong>Pattern:&lt;/strong> When it is required to find the median of a list, where the list grows continuously.
&lt;/div>
&lt;/div>
&lt;p>The &lt;strong>median&lt;/strong> is the middle value in an ordered integer list. If the size of the list is even, there is no middle value and the median is the mean of the two middle values.&lt;/p>
&lt;ul>
&lt;li>For example, for &lt;code>arr = [2,3,4]&lt;/code>, the median is &lt;code>3&lt;/code>.&lt;/li>
&lt;li>For example, for &lt;code>arr = [2,3]&lt;/code>, the median is &lt;code>(2 + 3) / 2 = 2.5&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Implement the MedianFinder class:&lt;/p>
&lt;ul>
&lt;li>&lt;code>MedianFinder()&lt;/code> initializes the MedianFinder object.&lt;/li>
&lt;li>&lt;code>void addNum(int num)&lt;/code> adds the integer num from the data stream to the data structure.&lt;/li>
&lt;li>&lt;code>double findMedian()&lt;/code> returns the median of all elements so far. Answers within &lt;code>10^-5&lt;/code> of the actual answer will be accepted.&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> &lt;br>
[&amp;ldquo;MedianFinder&amp;rdquo;, &amp;ldquo;addNum&amp;rdquo;, &amp;ldquo;addNum&amp;rdquo;, &amp;ldquo;findMedian&amp;rdquo;, &amp;ldquo;addNum&amp;rdquo;, &amp;ldquo;findMedian&amp;rdquo;] &lt;br>
[[], [1], [2], [], [3], []] &lt;br>
&lt;strong>Output:&lt;/strong> &lt;br>
[null, null, null, 1.5, null, 2.0] &lt;br>
&lt;details class="spoiler " id="spoiler-11">
&lt;summary>&lt;strong>Explanation&lt;/strong>&lt;/summary>
&lt;p>&lt;blockquote>
&lt;p>MedianFinder medianFinder = new MedianFinder(); &lt;br>
medianFinder.addNum(1); // arr = [1] &lt;br>
medianFinder.addNum(2); // arr = [1, 2] &lt;br>
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2) &lt;br>
medianFinder.addNum(3); // arr[1, 2, 3] &lt;br>
medianFinder.findMedian(); // return 2.0&lt;/p>
&lt;/blockquote>
&lt;/p>
&lt;/details>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Method 1:&lt;/strong>&lt;/p>
&lt;h4 id="key-ideas-5">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>use an array to store the stream of numbers&lt;/li>
&lt;li>appending to the array is &lt;code>O(1)&lt;/code>&lt;/li>
&lt;li>To find the median, sort the array and compute the median index based on the length of the array; &lt;code>O(nlogn)&lt;/code>&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-12">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class MedianFinder:
def __init__(self):
self.data_stream = []
def addNum(self, num: int) -&amp;gt; None:
self.data_stream.append(num) # O(1)
def findMedian(self) -&amp;gt; float:
m = len(self.data_stream)
self.data_stream.sort() # O(nlogn)
idx = m//2
if m % 2 != 0:
median = self.data_stream[idx]
else:
median = (self.data_stream[idx] + self.data_stream[idx-1])/2
return median
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;p>&lt;strong>Method 2:&lt;/strong>&lt;/p>
&lt;h4 id="key-ideas-6">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>Maintain two heaps to store the lower and upper halves of the stream of numbers
&lt;ul>
&lt;li>The lower half consists of small numbers of data stream; max-heap&lt;/li>
&lt;li>The upper half consists of large numbers of data stream; min-heap&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>By using two heaps, we have a slight tradeoff in the time complexity of &lt;code>addNum&lt;/code> to &lt;code>O(logn)&lt;/code> instead of &lt;code>O(1)&lt;/code>
&lt;ul>
&lt;li>By default, we always add a new number to the small number heap&lt;/li>
&lt;li>After adding the number to the small heap, we can check for certain properties to see if we need to balance the heaps
&lt;ul>
&lt;li>&lt;strong>Property 1:&lt;/strong> Difference between the sizes of the two heaps should be at most &lt;code>1&lt;/code>
&lt;ul>
&lt;li>If it is not satisfied, then pop and push the number to the other heap&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Property 2:&lt;/strong> The root of the min-heap should be larger than the root of the max-heap
&lt;ul>
&lt;li>If it is not satisfied
&lt;ul>
&lt;li>pop the root of the max-heap and push it to the min-heap&lt;/li>
&lt;li>pop the root of the min-heap and push it to the max-heap&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;figure id="figure-maintain-two-heaps-to-optimize-findmedian">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Maintain two heaps to optimize `findMedian()`" srcset="
/media/leetcode/Find%20median%20in%20data%20stream_hu3f1906e39283d490ee9367d99c61924b_14657_d9bb550aeb47c68445ffcae143ee19eb.webp 400w,
/media/leetcode/Find%20median%20in%20data%20stream_hu3f1906e39283d490ee9367d99c61924b_14657_a28eb654018de6eeeaf48e483b127aea.webp 760w,
/media/leetcode/Find%20median%20in%20data%20stream_hu3f1906e39283d490ee9367d99c61924b_14657_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/Find%20median%20in%20data%20stream_hu3f1906e39283d490ee9367d99c61924b_14657_d9bb550aeb47c68445ffcae143ee19eb.webp"
width="453"
height="257"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Maintain two heaps to optimize &lt;code>findMedian()&lt;/code>
&lt;/figcaption>&lt;/figure>
&lt;ul>
&lt;li>As we have two heaps to store the stream of numbers, the time complexity of &lt;code>findMedian&lt;/code> is &lt;code>O(1)&lt;/code>
&lt;ul>
&lt;li>&lt;em>Why?&lt;/em> Because we know that the median can be computed from the roots of two heaps, as atmost one heap will have one more element than the other.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-14">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import heapq
class MedianFinder:
def __init__(self):
self.sn = [] # heap for small numbers
self.ln = [] # heap for large numbers
def addNum(self, num: int) -&amp;gt; None:
# 1. Add it to sn and check if all the properties are satisfied
# Prop 1: Difference in the sn and ln should at most 1
# Prop 2: Max value in the sn should be less than min value in the ln
heapq.heappush(self.sn, -num)
if len(self.sn) &amp;gt; 1 + len(self.ln):
val = -1*heapq.heappop(self.sn)
heapq.heappush(self.ln, val)
if len(self.ln) &amp;gt; 1 + len(self.sn):
val = heapq.heappop(self.ln)
heapq.heappush(self.sn, -val)
if self.sn and self.ln and self.sn[0] &amp;lt; self.ln[0]:
val = -1*heapq.heappop(self.sn)
heapq.heappush(self.ln, val)
val = heapq.heappop(self.ln)
heapq.heappush(self.sn, -val)
def findMedian(self) -&amp;gt; float:
if len(self.sn) &amp;gt; len(self.ln):
# there are odd number of elements
return -1 * self.sn[0]
elif len(self.ln) &amp;gt; len(self.sn):
return self.ln[0]
v1 = self.ln[0]
v2 = -1*self.sn[0]
return (v1+v2)/2
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="references">References&lt;/h3>
&lt;section class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1" role="doc-endnote">
&lt;p>&lt;a href="https://realpython.com/python-heapq-module/" target="_blank" rel="noopener">https://realpython.com/python-heapq-module/&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/section></description></item><item><title>5. Trees and Tries</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/5.-trees-and-tries/</link><pubDate>Sat, 30 Jul 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/5.-trees-and-tries/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-general-introduction">A. General Introduction&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#i-key-methods">I. Key Methods&lt;/a>&lt;/li>
&lt;li>&lt;a href="#ii-binary-search-tree-bst-properties">II. Binary Search Tree (BST) Properties&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#b-leetcode-problems">B. Leetcode problems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#226-invert-binary-tree">226. Invert Binary Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#543-diameter-of-binary-tree">543. Diameter of Binary Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#104-maximum-depth-of-binary-tree">104. Maximum Depth of Binary Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#110-balanced-binary-tree">110. Balanced Binary Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#100-same-tree">100. Same Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#572-subtree-of-another-tree">572. Subtree of Another Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#102-binary-tree-level-order-traversal">102. Binary Tree Level Order Traversal&lt;/a>&lt;/li>
&lt;li>&lt;a href="#199-binary-tree-right-side-view">199. Binary Tree Right Side View&lt;/a>&lt;/li>
&lt;li>&lt;a href="#1448-count-good-nodes-in-binary-tree">1448. Count Good Nodes in Binary Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#98-validate-binary-search-tree">98. Validate Binary Search Tree&lt;/a>&lt;/li>
&lt;li>&lt;a href="#230-kth-smallest-element-in-a-bst">230. Kth Smallest Element in a BST&lt;/a>&lt;/li>
&lt;li>&lt;a href="#105-construct-binary-tree-from-preorder-and-inorder-traversal">105. Construct Binary Tree from Preorder and Inorder Traversal&lt;/a>&lt;/li>
&lt;li>&lt;a href="#124-binary-tree-maximum-path-sum">124. Binary Tree Maximum Path Sum&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;h3 id="i-key-methods">I. Key Methods&lt;/h3>
&lt;ol>
&lt;li>Identify the base case - &lt;em>what to do when it reaches the leaf or root node?&lt;/em>&lt;/li>
&lt;li>Recursive calls to each child node&lt;/li>
&lt;li>Identify what needs to be calculated with the information from the child nodes&lt;/li>
&lt;li>Return the calculated result&lt;/li>
&lt;/ol>
&lt;h3 id="ii-binary-search-tree-bst-properties">II. Binary Search Tree (BST) Properties&lt;/h3>
&lt;ol>
&lt;li>&lt;em>Inorder traversal&lt;/em> gives the sorted order of the BST&lt;/li>
&lt;li>All values in left subtree are smaller than the current node&lt;/li>
&lt;li>All values in right subtree are larger than the current node&lt;/li>
&lt;/ol>
&lt;h2 id="b-leetcode-problems">B. Leetcode problems&lt;/h2>
&lt;h3 id="226-invert-binary-tree">226. Invert Binary Tree&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, invert the tree, and return its &lt;code>root&lt;/code>.&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsinvert-binary-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/invert-binary-tree/" srcset="
/media/leetcode/invert1-tree_hu9fa936c7182abd3d3e60c29d6ff082f1_34272_e36e68ecbd388597d320bac2a98ff4c1.webp 400w,
/media/leetcode/invert1-tree_hu9fa936c7182abd3d3e60c29d6ff082f1_34272_d3524dd0207305d52a0b4654a0b1f010.webp 760w,
/media/leetcode/invert1-tree_hu9fa936c7182abd3d3e60c29d6ff082f1_34272_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/invert1-tree_hu9fa936c7182abd3d3e60c29d6ff082f1_34272_e36e68ecbd388597d320bac2a98ff4c1.webp"
width="500px"
height="251"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/invert-binary-tree/">https://leetcode.com/problems/invert-binary-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;h5 id="key-ideas">Key Ideas&lt;/h5>
&lt;ul>
&lt;li>Invert the tree by swapping the left and right children of each node.&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def invertTree(self, root: Optional[TreeNode]) -&amp;gt; Optional[TreeNode]:
if root is None or root.left == None and root.right == None:
return root
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="543-diameter-of-binary-tree">543. Diameter of Binary Tree&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, return the length of the diameter of the tree.&lt;/p>
&lt;p>The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the &lt;code>root&lt;/code>.&lt;/p>
&lt;p>The length of a path between two nodes is represented by the number of edges between them.&lt;/p>
&lt;h4 id="key-ideas-1">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> The diameter of an empty node is 0.&lt;/li>
&lt;li>&lt;code>@RecursiveCase&lt;/code> The diameter of a node is the maximum of the diameter of its left and right subtrees.
&lt;ul>
&lt;li>Return the max height of the subtrees plus 1 (&lt;em>accounts for the edge that connects it to parent node&lt;/em>).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-3">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python"># Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -&amp;gt; int:
result = 0 # global state that is set at each level
def traverse(root:TreeNode):
if not root:
return 0
rh = traverse(root.right)
lh = traverse(root.left)
nonlocal result
result = max(result, rh+lh)
return max(lh, rh) + 1
traverse(root)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="104-maximum-depth-of-binary-tree">104. Maximum Depth of Binary Tree&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, return its maximum depth.&lt;/p>
&lt;p>A binary tree&amp;rsquo;s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsmaximum-depth-of-binary-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/maximum-depth-of-binary-tree/" srcset="
/media/leetcode/tmp-tree_hu29c6579146da09e76aff3654bcd26093_12823_5e8e2b2710e39521cdae252812117483.webp 400w,
/media/leetcode/tmp-tree_hu29c6579146da09e76aff3654bcd26093_12823_01d98c9b84d64fb2c925f06cbc08b133.webp 760w,
/media/leetcode/tmp-tree_hu29c6579146da09e76aff3654bcd26093_12823_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/tmp-tree_hu29c6579146da09e76aff3654bcd26093_12823_5e8e2b2710e39521cdae252812117483.webp"
width="300px"
height="292"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/maximum-depth-of-binary-tree/">https://leetcode.com/problems/maximum-depth-of-binary-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,9,20,null,null,15,7] &lt;br>
&lt;strong>Output:&lt;/strong> 3&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-2">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> The depth of an empty node is 0.&lt;/li>
&lt;li>&lt;code>@RecursiveCase&lt;/code> Check the max depth of right and left subtrees.
&lt;ul>
&lt;li>Return the max of the two plus 1 (To include the height of the current node).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-5">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -&amp;gt; int:
if not root:
return 0
depth = 0
if root.right:
rd = self.maxDepth(root.right)
depth = max(depth, rd)
if root.left:
ld = self.maxDepth(root.left)
depth = max(depth, ld)
return depth + 1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="110-balanced-binary-tree">110. Balanced Binary Tree&lt;/h3>
&lt;p>Given a binary tree, determine if it is height-balanced.&lt;/p>
&lt;p>For this problem, a height-balanced binary tree is defined as:&lt;/p>
&lt;blockquote>
&lt;p>a binary tree in which the left and right subtrees of every node differ in height by no more than 1.&lt;/p>
&lt;/blockquote>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsbalanced-binary-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/balanced-binary-tree/" srcset="
/media/leetcode/balance_1_hu09ea994753ce544c034b0312f33f826f_10768_8fc42ea4cc8ad05e531644b877a40614.webp 400w,
/media/leetcode/balance_1_hu09ea994753ce544c034b0312f33f826f_10768_26b98ddc94b08c4d86a941c8e6813138.webp 760w,
/media/leetcode/balance_1_hu09ea994753ce544c034b0312f33f826f_10768_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/balance_1_hu09ea994753ce544c034b0312f33f826f_10768_8fc42ea4cc8ad05e531644b877a40614.webp"
width="342"
height="221"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/balanced-binary-tree/">https://leetcode.com/problems/balanced-binary-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,9,20,null,null,15,7] &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-3">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> The height of an empty node is zero.&lt;/li>
&lt;li>&lt;code>@RecursiveCase&lt;/code> The height of a node is the maximum of the height of its left and right subtrees.
&lt;ul>
&lt;li>At every node, calculate if the difference in height between the left and right subtrees is greater than 1.
&lt;ul>
&lt;li>If so, set the balanced set to false.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Return the max height of the subtrees plus 1.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-7">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -&amp;gt; bool:
balanced = True
def dfs(root:TreeNode) -&amp;gt; int:
if root is None:
return 0
lh = dfs(root.left)
rh = dfs(root.right)
if abs(lh-rh) &amp;gt; 1:
nonlocal balanced
balanced = False
return max(lh, rh) + 1
dfs(root)
return balanced
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="100-same-tree">100. Same Tree&lt;/h3>
&lt;p>Given the roots of two binary trees &lt;code>p&lt;/code> and &lt;code>q&lt;/code>, write a function to check if they are the same or not.&lt;/p>
&lt;p>Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemssame-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/same-tree/" srcset="
/media/leetcode/same-tree_huc60ecf4321f6002339089e53666d2aad_13336_f307e57a1dc780f74f0627d9a7be6955.webp 400w,
/media/leetcode/same-tree_huc60ecf4321f6002339089e53666d2aad_13336_3b35f4fbd80308e77ce430f135867dd3.webp 760w,
/media/leetcode/same-tree_huc60ecf4321f6002339089e53666d2aad_13336_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/same-tree_huc60ecf4321f6002339089e53666d2aad_13336_f307e57a1dc780f74f0627d9a7be6955.webp"
width="622"
height="182"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/same-tree/">https://leetcode.com/problems/same-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> p = [1,2,3], q = [1,2,3] &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-4">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If both trees are empty, return true.&lt;/li>
&lt;li>&lt;code>@RecursiveCase&lt;/code> If the trees are not empty, compare the values of the root nodes.
&lt;ul>
&lt;li>If they are not equal, return false.&lt;/li>
&lt;li>Otherwise, compare the left and right subtrees.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-9">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -&amp;gt; bool:
if not p and not q:
return True
if p and q and p.val == q.val:
l = self.isSameTree(p.left, q.left)
r = self.isSameTree(p.right, q.right)
if l and r:
return True
return False
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="572-subtree-of-another-tree">572. Subtree of Another Tree&lt;/h3>
&lt;p>Given the roots of two binary trees &lt;code>root&lt;/code> and &lt;code>subRoot&lt;/code>, return &lt;code>true&lt;/code> if there is a subtree of &lt;code>root&lt;/code> with the same structure and node values of &lt;code>subRoot&lt;/code> and &lt;code>false&lt;/code> otherwise.&lt;/p>
&lt;p>A subtree of a binary tree &lt;code>tree&lt;/code> is a tree that consists of a node in &lt;code>tree&lt;/code> and all of this node&amp;rsquo;s descendants. The tree &lt;code>tree&lt;/code> could also be considered as a subtree of itself.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemssubtree-of-another-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/subtree-of-another-tree/" srcset="
/media/leetcode/subtree1-tree_hu1b2d673205ec8b2b30fe461e7d157238_26750_7728ea8fa5e932f5c962228109c627aa.webp 400w,
/media/leetcode/subtree1-tree_hu1b2d673205ec8b2b30fe461e7d157238_26750_84af74858fb8eb62b95b46a20b5c935e.webp 760w,
/media/leetcode/subtree1-tree_hu1b2d673205ec8b2b30fe461e7d157238_26750_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/subtree1-tree_hu1b2d673205ec8b2b30fe461e7d157238_26750_7728ea8fa5e932f5c962228109c627aa.webp"
width="532"
height="400"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/subtree-of-another-tree/">https://leetcode.com/problems/subtree-of-another-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,4,5,1,2], subRoot = [4,1,2] &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-5">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Use &lt;code>isSameTree&lt;/code> to check the equality of the trees&lt;/li>
&lt;li>&lt;code>@BaseCase&lt;/code> If root is empty, return false; because there is no subtree in an empty tree.&lt;/li>
&lt;li>&lt;code>@BaseCase&lt;/code> If subRoot is empty, return true; because an empty subtree is a subtree of a tree with even one node&lt;/li>
&lt;li>&lt;code>@RecursiveCase&lt;/code> Check if left subtree or right subtree is the &lt;code>subRoot&lt;/code>&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-11">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">class Solution:
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -&amp;gt; bool:
if not p and not q:
return True
if p and q and p.val == q.val:
l = self.isSameTree(p.left, q.left)
r = self.isSameTree(p.right, q.right)
if l and r:
return True
return False
def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -&amp;gt; bool:
if not root:
return False
if not subRoot:
return True
if self.isSameTree(root, subRoot):
return True
return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="102-binary-tree-level-order-traversal">102. Binary Tree Level Order Traversal&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsbinary-tree-level-order-traversal">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/binary-tree-level-order-traversal/" srcset="
/media/leetcode/tree1-level_hua3415daddb002305fa2c455ec118f3c7_11387_f33a6a8cd4bbbdf0bad3bd3e208fd7e0.webp 400w,
/media/leetcode/tree1-level_hua3415daddb002305fa2c455ec118f3c7_11387_bdc185bb746989e932b0137c2de86fc1.webp 760w,
/media/leetcode/tree1-level_hua3415daddb002305fa2c455ec118f3c7_11387_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/tree1-level_hua3415daddb002305fa2c455ec118f3c7_11387_f33a6a8cd4bbbdf0bad3bd3e208fd7e0.webp"
width="277"
height="302"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/binary-tree-level-order-traversal/">https://leetcode.com/problems/binary-tree-level-order-traversal/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,9,20,null,null,15,7] &lt;br>
&lt;strong>Output:&lt;/strong> [[3],[9,20],[15,7]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-6">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the root is empty, return an empty list.&lt;/li>
&lt;li>Used a multi-source BFS approach to traverse each level of the tree&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-13">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -&amp;gt; List[List[int]]:
if not root:
return []
result = []
queue = deque([root])
while queue:
layer = []
m = len(queue)
for _ in range(m):
node = queue.popleft()
layer.append(node.val)
# add children
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(layer)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="199-binary-tree-right-side-view">199. Binary Tree Right Side View&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, imagine yourself standing on the &lt;strong>right side&lt;/strong> of it, return the values of the nodes you can see ordered from top to bottom.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsbinary-tree-right-side-view">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/binary-tree-right-side-view/" srcset="
/media/leetcode/tree-right-side-view_huadd665b549cd854e2788da4a94005cb1_14835_dcc35beec88995751a705435adc5771c.webp 400w,
/media/leetcode/tree-right-side-view_huadd665b549cd854e2788da4a94005cb1_14835_39d3e6382db6e35a7c1e6d52dcc57b67.webp 760w,
/media/leetcode/tree-right-side-view_huadd665b549cd854e2788da4a94005cb1_14835_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/tree-right-side-view_huadd665b549cd854e2788da4a94005cb1_14835_dcc35beec88995751a705435adc5771c.webp"
width="401"
height="301"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/binary-tree-right-side-view/">https://leetcode.com/problems/binary-tree-right-side-view/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [1,2,3,null,5,null,4] &lt;br>
&lt;strong>Output:&lt;/strong> [1, 3, 4]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-7">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the root is empty, return an empty list.&lt;/li>
&lt;li>Used a multi-source BFS approach to traverse each level of the tree
&lt;ul>
&lt;li>for each level, have a value that is overwritten each node in the level&lt;/li>
&lt;li>At the end of the loop, the value would be the last node at the level&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-15">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -&amp;gt; List[int]:
if not root:
return []
result = []
queue = deque([root])
while queue:
m = len(queue)
val = None
for _ in range(m):
node = queue.popleft()
val = node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
if val is not None:
result.append(val)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="1448-count-good-nodes-in-binary-tree">1448. Count Good Nodes in Binary Tree&lt;/h3>
&lt;p>Given a binary tree &lt;code>root&lt;/code>, a node X in the tree is named good if in the path from root to X there are no nodes with a value greater than X.&lt;/p>
&lt;p>Return the number of good nodes in the binary tree.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemscount-good-nodes-in-binary-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/count-good-nodes-in-binary-tree/" srcset="
/media/leetcode/count_goods_sample_1_huc52f05f532272b62d732a66ca8671fd8_7593_dc8b3aa95e7711049a7cfef397d1d5ad.webp 400w,
/media/leetcode/count_goods_sample_1_huc52f05f532272b62d732a66ca8671fd8_7593_67d19493b7ec230b002a81afdee9eaeb.webp 760w,
/media/leetcode/count_goods_sample_1_huc52f05f532272b62d732a66ca8671fd8_7593_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/count_goods_sample_1_huc52f05f532272b62d732a66ca8671fd8_7593_dc8b3aa95e7711049a7cfef397d1d5ad.webp"
width="263"
height="156"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/count-good-nodes-in-binary-tree/">https://leetcode.com/problems/count-good-nodes-in-binary-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,1,4,3,null,1,5] &lt;br>
&lt;strong>Output:&lt;/strong> 4 &lt;br>
&lt;strong>Explanation:&lt;/strong> Nodes in blue are good. &lt;br>
Root Node (3) is always a good node. &lt;br>
Node 4 -&amp;gt; (3,4) is the maximum value in the path starting from the root. &lt;br>
Node 5 -&amp;gt; (3,4,5) is the maximum value in the path. &lt;br>
Node 3 -&amp;gt; (3,1,3) is the maximum value in the path.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-8">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@MainCase&lt;/code> Pass a maxval argument which is the maximum value in the path
&lt;ul>
&lt;li>If the current node&amp;rsquo;s value is greater than the maxval, then the node is good and the maxval is updated to the current node&amp;rsquo;s value&lt;/li>
&lt;li>Traverse the right and left subtrees&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-17">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def goodNodes(self, root: TreeNode) -&amp;gt; int:
if not root.left and not root.right:
return 1
result = 0
def dfs(root:TreeNode, maxval:int) -&amp;gt; None:
if root.val &amp;gt;= maxval:
nonlocal result
result += 1
maxval = root.val
if root.right:
dfs(root.right, maxval)
if root.left:
dfs(root.left, maxval)
dfs(root, root.val)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="98-validate-binary-search-tree">98. Validate Binary Search Tree&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, &lt;em>determine if it is a valid binary search tree (BST).&lt;/em>&lt;/p>
&lt;p>A valid BST is defined as follows:&lt;/p>
&lt;ul>
&lt;li>The left subtree of a node contains only nodes with keys less than the node&amp;rsquo;s key.&lt;/li>
&lt;li>The right subtree of a node contains only nodes with keys greater than the node&amp;rsquo;s key.&lt;/li>
&lt;li>Both the left and right subtrees must also be binary search trees.&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsvalidate-binary-search-tree">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/validate-binary-search-tree/" srcset="
/media/leetcode/tree1-validate-bst_huaeb059b75d0c91d57bc161c2ceca8ca2_6825_f876a94db3a7a412f880e5ca7c6440b6.webp 400w,
/media/leetcode/tree1-validate-bst_huaeb059b75d0c91d57bc161c2ceca8ca2_6825_2ede03ebb632b54457314242958af841.webp 760w,
/media/leetcode/tree1-validate-bst_huaeb059b75d0c91d57bc161c2ceca8ca2_6825_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/tree1-validate-bst_huaeb059b75d0c91d57bc161c2ceca8ca2_6825_f876a94db3a7a412f880e5ca7c6440b6.webp"
width="302"
height="182"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/validate-binary-search-tree/">https://leetcode.com/problems/validate-binary-search-tree/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [2,1,3] &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-9">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the root is empty, return True.&lt;/li>
&lt;li>Have a max and min value at each node; If the value of the node is greater than the max value, or less than the min value, then the tree is not a BST&lt;/li>
&lt;li>Check the left and right subtrees&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-19">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -&amp;gt; bool:
if not root.right and not root.left:
return True
def dfs(root:TreeNode, maxval:float, minval:float):
if not root:
return True
if root.val &amp;gt;= maxval or root.val &amp;lt;= minval:
return False
r = dfs(root.right, maxval, root.val)
l = dfs(root.left, root.val, minval)
return r and l
result = dfs(root, float(&amp;quot;inf&amp;quot;), float(&amp;quot;-inf&amp;quot;))
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="230-kth-smallest-element-in-a-bst">230. Kth Smallest Element in a BST&lt;/h3>
&lt;p>Given the &lt;code>root&lt;/code> of a binary search tree, and an integer &lt;code>k&lt;/code>, return the &lt;code>kth&lt;/code> smallest value (1-indexed) of all the values of the nodes in the tree.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemskth-smallest-element-in-a-bst">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/kth-smallest-element-in-a-bst/" srcset="
/media/leetcode/kthtree1_hu5c4cc9efcd67fae31e6f3111da835336_8694_d4effe76197432f96104e6f8627c0fcd.webp 400w,
/media/leetcode/kthtree1_hu5c4cc9efcd67fae31e6f3111da835336_8694_cbbdae1942558b4c89fa4bf405e6ba93.webp 760w,
/media/leetcode/kthtree1_hu5c4cc9efcd67fae31e6f3111da835336_8694_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/kthtree1_hu5c4cc9efcd67fae31e6f3111da835336_8694_d4effe76197432f96104e6f8627c0fcd.webp"
width="212"
height="301"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/kth-smallest-element-in-a-bst/">https://leetcode.com/problems/kth-smallest-element-in-a-bst/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [3,1,4,null,2], k = 1 &lt;br>
&lt;strong>Output:&lt;/strong> 1 \&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-10">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>Traverse through the tree in order and return the kth value&lt;/li>
&lt;li>Return the &lt;code>k-1&lt;/code>th value as it is 1-indexed&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-21">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def kthSmallest(self, root: Optional[TreeNode], k: int) -&amp;gt; int:
heap = []
def traverse(root: TreeNode):
if not root:
return
if root.left:
traverse(root.left)
heap.append(root.val)
if root.right:
traverse(root.right)
traverse(root)
return heap[k-1]
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="105-construct-binary-tree-from-preorder-and-inorder-traversal">105. Construct Binary Tree from Preorder and Inorder Traversal&lt;/h3>
&lt;p>Given two integer arrays &lt;code>preorder&lt;/code> and &lt;code>inorder&lt;/code> where &lt;code>preorder&lt;/code> is the preorder traversal of a binary tree and &lt;code>inorder&lt;/code> is the inorder traversal of the same tree, construct and return the binary tree.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsconstruct-binary-tree-from-preorder-and-inorder-traversal">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/" srcset="
/media/leetcode/pre-order-in-order-tree_hu65b53a4f2015dd85846facaa3087e9e9_11138_9717588d0f38b80a2271760633040190.webp 400w,
/media/leetcode/pre-order-in-order-tree_hu65b53a4f2015dd85846facaa3087e9e9_11138_7f301b31f0b540e7581fc3a4493ed099.webp 760w,
/media/leetcode/pre-order-in-order-tree_hu65b53a4f2015dd85846facaa3087e9e9_11138_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/pre-order-in-order-tree_hu65b53a4f2015dd85846facaa3087e9e9_11138_9717588d0f38b80a2271760633040190.webp"
width="277"
height="302"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/">https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] &lt;br>
&lt;strong>Output:&lt;/strong> [3,9,20,null,null,15,7]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-11">Key Ideas:&lt;/h4>
&lt;figure id="figure-key-idea-of-the-solution">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Key Idea of the solution" srcset="
/media/leetcode/inorder-preorder-explanation_hu9cd3c785219b8e7c1b1024457c9bb87e_64219_d6a62f2b09737140f42c6b2d10229f15.webp 400w,
/media/leetcode/inorder-preorder-explanation_hu9cd3c785219b8e7c1b1024457c9bb87e_64219_966736f69f5fe9c16a10eedd736e910e.webp 760w,
/media/leetcode/inorder-preorder-explanation_hu9cd3c785219b8e7c1b1024457c9bb87e_64219_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/inorder-preorder-explanation_hu9cd3c785219b8e7c1b1024457c9bb87e_64219_d6a62f2b09737140f42c6b2d10229f15.webp"
width="500px"
height="303"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Key Idea of the solution
&lt;/figcaption>&lt;/figure>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the length of the &lt;code>preorder&lt;/code> and &lt;code>inorder&lt;/code> is 0, return None&lt;/li>
&lt;li>In &lt;code>preorder&lt;/code> the first element is the root of the tree/subtree
&lt;ul>
&lt;li>Find the index of the root in &lt;code>inorder&lt;/code> and split the &lt;code>preorder&lt;/code> and &lt;code>inorder&lt;/code> into two subarrays&lt;/li>
&lt;li>Recursively call the function on the subarrays&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-24">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -&amp;gt; Optional[TreeNode]:
if not preorder and not inorder:
return None
root = TreeNode(preorder[0])
rootIdx = inorder.index(preorder[0])
root.left = self.buildTree(preorder[1:rootIdx+1], inorder[:rootIdx])
root.right = self.buildTree(preorder[rootIdx+1:], inorder[rootIdx+1:])
return root
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="124-binary-tree-maximum-path-sum">124. Binary Tree Maximum Path Sum&lt;/h3>
&lt;p>A path in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence at most once. Note that the path does not need to pass through the root.&lt;/p>
&lt;p>The path sum of a path is the sum of the node&amp;rsquo;s values in the path.&lt;/p>
&lt;p>Given the &lt;code>root&lt;/code> of a binary tree, return the maximum path sum of any non-empty path.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsbinary-tree-maximum-path-sum">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/binary-tree-maximum-path-sum/" srcset="
/media/leetcode/exx2-max-path_hua0a51f4ff1c390060df494052968420e_13062_d0065a610b58efdef1c1382867831809.webp 400w,
/media/leetcode/exx2-max-path_hua0a51f4ff1c390060df494052968420e_13062_62e9af0fbd5fe9c52f14c9451c5e6b8e.webp 760w,
/media/leetcode/exx2-max-path_hua0a51f4ff1c390060df494052968420e_13062_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/exx2-max-path_hua0a51f4ff1c390060df494052968420e_13062_d0065a610b58efdef1c1382867831809.webp"
width="431"
height="302"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/binary-tree-maximum-path-sum/">https://leetcode.com/problems/binary-tree-maximum-path-sum/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> root = [-10,9,20,null,null,15,7] &lt;br>
&lt;strong>Output:&lt;/strong> 42
&lt;strong>Explanation:&lt;/strong> 5 + 20 + 7 = 42&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-12">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the root is empty, return 0&lt;/li>
&lt;li>The idea is very similar to &lt;strong>finding diameter of a tree&lt;/strong> - we can find the maximum path sum of any path in the tree
&lt;ul>
&lt;li>Initalize the max path with root value&lt;/li>
&lt;li>Traverse through the tree and at each node, the max value can be &lt;code>maxvalue&lt;/code> or &lt;code>&amp;lt;right-subtree-cost&amp;gt;+ root.val+&amp;lt;left-subtree-cost&amp;gt;&lt;/code>&lt;/li>
&lt;li>Return the sum of maximum of left and right subtree max values and the root value&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-26">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -&amp;gt; int:
maxPathVal = root.val
if not root.left and not root.right:
return root.val
def dfs(root) -&amp;gt; None:
if not root:
return 0
lp = max(0, dfs(root.left))
rp = max(0, dfs(root.right))
nonlocal maxPathVal
maxPathVal = max(maxPathVal, lp+rp+root.val)
return max(lp,rp) + root.val
dfs(root)
return maxPathVal
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>6. Backtracking</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/6.-backtracking/</link><pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/6.-backtracking/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-general-idea">A. General Idea&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-leetcode-problems">B. Leetcode problems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#78-subsets">78. Subsets&lt;/a>&lt;/li>
&lt;li>&lt;a href="#90-subsets-ii">90. Subsets II&lt;/a>&lt;/li>
&lt;li>&lt;a href="#39-combination-sum">39. Combination Sum&lt;/a>&lt;/li>
&lt;li>&lt;a href="#17-letter-combinations-of-a-phone-number">17. Letter Combinations of a Phone Number&lt;/a>&lt;/li>
&lt;li>&lt;a href="#131-palindrome-partitioning">131. Palindrome Partitioning&lt;/a>&lt;/li>
&lt;li>&lt;a href="#79-word-search">79. Word Search&lt;/a>&lt;/li>
&lt;li>&lt;a href="#51-n-queens">51. N-Queens&lt;/a>&lt;/li>
&lt;li>&lt;a href="#40-combination-sum-ii">40. Combination Sum II&lt;/a>&lt;/li>
&lt;li>&lt;a href="#46-permutations">46. Permutations&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-general-idea">A. General Idea&lt;/h2>
&lt;p>The key &lt;em>intuition&lt;/em> to understand backtracking is to imagine and formulize a problem as decision tree.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Define the base case for the decision tree; Base case determines the terminal condition of a path in a decision tree.&lt;/p>
&lt;ul>
&lt;li>Out of bounds&lt;/li>
&lt;li>Reach a target sum or value&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Decide the actions to take in each node of the decision tree.&lt;/p>
&lt;ul>
&lt;li>Choose a candidate&lt;/li>
&lt;li>Prune the candidate&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Maintain a global state to store the results&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="b-leetcode-problems">B. Leetcode problems&lt;/h2>
&lt;h3 id="78-subsets">78. Subsets&lt;/h3>
&lt;p>Given an integer array &lt;code>nums&lt;/code> of &lt;strong>unique&lt;/strong> elements, return &lt;em>all possible subsets (the power set).&lt;/em>&lt;/p>
&lt;p>The solution set &lt;strong>must not&lt;/strong> contain duplicate subsets. Return the solution in &lt;strong>any order&lt;/strong>.&lt;/p>
&lt;p>Example 1:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> [1,2,3] &lt;br>
&lt;strong>Output:&lt;/strong> [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>The base case is when the index, &lt;code>i&lt;/code>, is out of bounds of the array.
&lt;ul>
&lt;li>Append the subset to result&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Action: Append a candidate at index &lt;code>i&lt;/code> to the subset and recursive call.
&lt;ul>
&lt;li>Prune the candidate at index &lt;code>i&lt;/code> and recursive call.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def subsets(self, nums: List[int]) -&amp;gt; List[List[int]]:
result = []
subset = []
def dfs(i):
if i &amp;gt;= len(nums): # base case - out of bounds
result.append(subset.copy())
return
subset.append(nums[i])
dfs(i+1)
subset.pop()
dfs(i+1)
dfs(0)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="90-subsets-ii">90. Subsets II&lt;/h3>
&lt;p>Given an integer array &lt;code>nums&lt;/code> that may contain duplicates, &lt;em>return all possible subsets (the power set).&lt;/em>&lt;/p>
&lt;p>The solution set &lt;strong>must not&lt;/strong> contain duplicate subsets. Return the solution in &lt;strong>any order.&lt;/strong>&lt;/p>
&lt;p>Example 1:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [1,2,2] &lt;br>
&lt;strong>Output:&lt;/strong> [[],[1],[1,2],[1,2,2],[2],[2,2]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>The base logic is same as &lt;code>78. subsets&lt;/code> problem.&lt;/li>
&lt;li>To handle duplicates, we sort the array to ensure duplicates are arranged consecutively.
&lt;ul>
&lt;li>In the case of pruning, ensure to increment &lt;code>i&lt;/code> till the next element is different.
&lt;ul>
&lt;li>&lt;em>Why?&lt;/em> This ensures that the right subtrees never contain the duplicate element.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">from typing import List
class Solution:
def subsetsWithDup(self, nums: List[int]) -&amp;gt; List[List[int]]:
result = []
m = len(nums)
# Algorithm:
# 1. Base case: idx &amp;gt;= len(nums): append to the result and return
# 2. Actions:
# 2.1 Include a number and call a recursive fn
# 2.2 Remove the number and call a recursive fn
nums.sort()
def generateSubsets(i,curr):
if i &amp;gt;= m:
result.append(curr.copy())
return
n = nums[i]
curr.append(n)
generateSubsets(i+1, curr)
curr.pop()
while i+1&amp;lt;m and nums[i] == nums[i+1]:
i += 1
generateSubsets(i+1, curr)
generateSubsets(0, []) # generate all the possible subsets without duplicates
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="39-combination-sum">39. Combination Sum&lt;/h3>
&lt;p>Given an array of distinct integers &lt;code>candidates&lt;/code> and a &lt;code>target&lt;/code> integer target, return a list of all unique combinations of candidates where the chosen numbers sum to &lt;code>target&lt;/code>. You may return the combinations in any order.&lt;/p>
&lt;p>The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.&lt;/p>
&lt;p>It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input.&lt;/p>
&lt;p>Example 1:&lt;/p>
&lt;blockquote>
&lt;p>Input: candidates = [2,3,6,7], target = 7 &lt;br>
Output: [[2,2,3],[7]]&lt;/p>
&lt;p>&lt;strong>Explanation:&lt;/strong>
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
7 is a candidate, and 7 = 7.
These are the only two combinations.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-2">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>There are multiple base cases for this problem&lt;/p>
&lt;ol>
&lt;li>when the sum of the array is greater than the target.&lt;/li>
&lt;li>when the sum of the array is equal to the target.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>The action is to append a candidate to the current subset and recursive call.&lt;/p>
&lt;ul>
&lt;li>Prune the candidate and recursive call.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-3">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">from typing import List
class Solution:
def combinationSum(self, candidates: List[int], target: int) -&amp;gt; List[List[int]]:
result = []
def dfs(decision_id:int, current_comb:List[int], current_sum:int):
# Identify and handle the base cases
if current_sum == target:
result.append(current_comb.copy())
return
if current_sum &amp;gt; target or decision_id &amp;gt;= len(candidates):
return
# Make the decisions and update the constraints
current_comb.append(candidates[decision_id])
dfs(decision_id, current_comb, current_sum + candidates[decision_id])
# Undo the decision and traverse another path
current_comb.pop()
dfs(decision_id+1, current_comb, current_sum)
dfs(0, [], 0)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="17-letter-combinations-of-a-phone-number">17. Letter Combinations of a Phone Number&lt;/h3>
&lt;p>Given a string containing digits from &lt;code>2-9&lt;/code> inclusive, return all possible letter combinations that the number could represent. Return the answer in &lt;strong>any order.&lt;/strong>&lt;/p>
&lt;p>A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.&lt;/p>
&lt;figure id="figure-httpsleetcodecomproblemsletter-combinations-of-a-phone-number">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="https://leetcode.com/problems/letter-combinations-of-a-phone-number/" srcset="
/media/leetcode/1200px-telephone-keypad2svg_huf506ac3ea9a7e1386acc70f90df9a1db_310876_91417077326af57208d8b02be9f778bf.webp 400w,
/media/leetcode/1200px-telephone-keypad2svg_huf506ac3ea9a7e1386acc70f90df9a1db_310876_40848c34302ea23bcf0aa2fc990b0f6a.webp 760w,
/media/leetcode/1200px-telephone-keypad2svg_huf506ac3ea9a7e1386acc70f90df9a1db_310876_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/1200px-telephone-keypad2svg_huf506ac3ea9a7e1386acc70f90df9a1db_310876_91417077326af57208d8b02be9f778bf.webp"
width="250px"
height="616"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
&lt;a href="https://leetcode.com/problems/letter-combinations-of-a-phone-number/">https://leetcode.com/problems/letter-combinations-of-a-phone-number/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;p>Example 1:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> &amp;ldquo;23&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> [&amp;ldquo;ad&amp;rdquo;, &amp;ldquo;ae&amp;rdquo;, &amp;ldquo;af&amp;rdquo;, &amp;ldquo;bd&amp;rdquo;, &amp;ldquo;be&amp;rdquo;, &amp;ldquo;bf&amp;rdquo;, &amp;ldquo;cd&amp;rdquo;, &amp;ldquo;ce&amp;rdquo;, &amp;ldquo;cf&amp;rdquo;]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-3">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>Base case is when the length of the combination is equal to the number of digits&lt;/li>
&lt;li>Generate a hashmap which maps the set of characters to the corresponding digit position&lt;/li>
&lt;li>Actions: Iterate through the set of character for a particular level and make a recursive call.&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-5">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def letterCombinations(self, digits: str) -&amp;gt; List[str]:
combinations = []
m = len(digits)
if m == 0:
return combinations
digits2char = {
&amp;quot;2&amp;quot;:&amp;quot;abc&amp;quot;,
&amp;quot;3&amp;quot;:&amp;quot;def&amp;quot;,
&amp;quot;4&amp;quot;:&amp;quot;ghi&amp;quot;,
&amp;quot;5&amp;quot;:&amp;quot;jkl&amp;quot;,
&amp;quot;6&amp;quot;:&amp;quot;mno&amp;quot;,
&amp;quot;7&amp;quot;:&amp;quot;pqrs&amp;quot;,
&amp;quot;8&amp;quot;:&amp;quot;tuv&amp;quot;,
&amp;quot;9&amp;quot;:&amp;quot;wxyz&amp;quot;,
}
chars = defaultdict(list)
for i, digit in enumerate(digits):
chars[i] = digits2char[digit]
def dfs(comb:str, level:int):
if len(comb) == m:
combinations.append(comb)
return
if len(comb) &amp;gt; m or level &amp;gt; m:
return
charsInLvl = chars[level]
for char in charsInLvl:
dfs(comb+char, level+1)
dfs(&amp;quot;&amp;quot;, 0)
return combinations
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="131-palindrome-partitioning">131. Palindrome Partitioning&lt;/h3>
&lt;p>Given a string &lt;code>s&lt;/code>, partition &lt;code>s&lt;/code> such that every substring of the partition is a &lt;em>palindrome&lt;/em>. Return all possible palindrome partitioning of &lt;code>s&lt;/code>.&lt;/p>
&lt;p>A &lt;strong>palindrome&lt;/strong> string is a string that reads the same backward as forward.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> s = &amp;ldquo;aab&amp;rdquo;
&lt;strong>Output:&lt;/strong> [[&amp;ldquo;a&amp;rdquo;,&amp;ldquo;a&amp;rdquo;,&amp;ldquo;b&amp;rdquo;],[&amp;ldquo;aa&amp;rdquo;,&amp;ldquo;b&amp;rdquo;]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-4">Key Ideas:&lt;/h4>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/media/leetcode/palin_partition_hu35750602ee3f35090af542c1795bb5a5_113345_b2bfcfc645b7b2ee02d729bedf3e7755.webp 400w,
/media/leetcode/palin_partition_hu35750602ee3f35090af542c1795bb5a5_113345_7bc6fa98efca11724ec25a4f6e8bd10b.webp 760w,
/media/leetcode/palin_partition_hu35750602ee3f35090af542c1795bb5a5_113345_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/palin_partition_hu35750602ee3f35090af542c1795bb5a5_113345_b2bfcfc645b7b2ee02d729bedf3e7755.webp"
width="300px"
height="742"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;ul>
&lt;li>Partition the string into substrings&lt;/li>
&lt;li>Check if the substring is a palindrome
&lt;ul>
&lt;li>If it is, add it to current_partition, increment idx position in string and call the recursive function
&lt;ul>
&lt;li>Pop the last element from current_partition&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>@BaseCase&lt;/code> If the idx is greater or equal to the length of the string, add the current_partition to the result and return&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-7">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def isPalindrome(self, s:str, l:int, r:int) -&amp;gt; bool:
&amp;quot;&amp;quot;&amp;quot;Checks if a string is palindrome&amp;quot;&amp;quot;&amp;quot;
while l&amp;lt;r:
if s[l] != s[r]:
return False
l += 1
r -= 1
return True
def partition(self, s: str) -&amp;gt; List[List[str]]:
if len(s) == 1:
return [[s]]
m = len(s)
result = []
current_partition = []
def traversePartition(idx:int):
&amp;quot;&amp;quot;&amp;quot;Add palindrome partitions to result list&amp;quot;&amp;quot;&amp;quot;
if idx &amp;gt;= m:
result.append(current_partition.copy())
return
for j in range(idx, m):
if self.isPalindrome(s, idx, j):
current_partition.append(s[idx:j+1])
traversePartition(j+1)
current_partition.pop()
# Exp Behav: Add palindrome partitions to the results
traversePartition(0)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="79-word-search">79. Word Search&lt;/h3>
&lt;p>Given an &lt;code>m x n&lt;/code> grid of characters &lt;code>board&lt;/code> and a string &lt;code>word&lt;/code>, return &lt;code>true&lt;/code> if &lt;code>word&lt;/code> exists in the grid.&lt;/p>
&lt;p>The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsword-search">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/word-search/" srcset="
/media/leetcode/word2_hu3ab7f630460a11ef2729c09876915671_13241_f9cf23627b76aa303e1df7d18c428bec.webp 400w,
/media/leetcode/word2_hu3ab7f630460a11ef2729c09876915671_13241_b8263b2e5469c5743aa93e2f13c2be54.webp 760w,
/media/leetcode/word2_hu3ab7f630460a11ef2729c09876915671_13241_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/word2_hu3ab7f630460a11ef2729c09876915671_13241_f9cf23627b76aa303e1df7d18c428bec.webp"
width="322"
height="242"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/word-search/">https://leetcode.com/problems/word-search/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> board = [[&amp;ldquo;A&amp;rdquo;,&amp;ldquo;B&amp;rdquo;,&amp;ldquo;C&amp;rdquo;,&amp;ldquo;E&amp;rdquo;],[&amp;ldquo;S&amp;rdquo;,&amp;ldquo;F&amp;rdquo;,&amp;ldquo;C&amp;rdquo;,&amp;ldquo;S&amp;rdquo;],[&amp;ldquo;A&amp;rdquo;,&amp;ldquo;D&amp;rdquo;,&amp;ldquo;E&amp;rdquo;,&amp;ldquo;E&amp;rdquo;]], word = &amp;ldquo;ABCCED&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-5">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@BaseCase&lt;/code> If the current index is greater or equal to the length of the string, return true; That is we have found the entire word through traversal&lt;/li>
&lt;li>Iterate through the neighboring cells and call the recursive function if the character at the current index is equal to the character at the current index in the string&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-9">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def exist(self, board: List[List[str]], word: str) -&amp;gt; bool:
m,n = len(board), len(board[0])
s = len(word)
DIRECTIONS = [(1,0), (0,1), (-1,0), (0,-1)]
check_boundaries = lambda x, y: x&amp;lt;m and x&amp;gt;=0 and y&amp;lt;n and y&amp;gt;=0
if s &amp;gt; m*n:
return False
def traverse(i, x, y):
if i &amp;gt;= len(word):
return True
for dx, dy in DIRECTIONS:
xx, yy = x+dx, y+dy
if check_boundaries(xx, yy) and board[xx][yy] == word[i]:
tmp = board[xx][yy]
board[xx][yy] = &amp;quot;#&amp;quot;
if traverse(i+1, xx, yy):
return True
board[xx][yy] = tmp
return False
for i in range(m):
for j in range(n):
if board[i][j] == word[0]:
board[i][j] = &amp;quot;#&amp;quot;
if traverse(1, i,j):
return True
board[i][j] = word[0]
return False
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="51-n-queens">51. N-Queens&lt;/h3>
&lt;p>The n-queens puzzle is the problem of placing &lt;code>n&lt;/code> queens on an &lt;code>n x n&lt;/code> chessboard such that no two queens attack each other.&lt;/p>
&lt;p>Given an integer &lt;code>n&lt;/code>, return all distinct solutions to the &lt;code>n-queens&lt;/code> puzzle. You may return the answer in any order.&lt;/p>
&lt;p>Each solution contains a distinct board configuration of the n-queens' placement, where &lt;code>'Q'&lt;/code> and &lt;code>'.'&lt;/code> both indicate a queen and an empty space, respectively.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsn-queens">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/n-queens/" srcset="
/media/leetcode/queens_hucc691c85a337a2780f91a17d5d713605_31523_da3f8c6eb463714a32b73f5f69df211a.webp 400w,
/media/leetcode/queens_hucc691c85a337a2780f91a17d5d713605_31523_cbcbe718f9836f222687f10fa0e993d5.webp 760w,
/media/leetcode/queens_hucc691c85a337a2780f91a17d5d713605_31523_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/queens_hucc691c85a337a2780f91a17d5d713605_31523_da3f8c6eb463714a32b73f5f69df211a.webp"
width="450px"
height="322"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/n-queens/">https://leetcode.com/problems/n-queens/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> n = 4 &lt;br>
&lt;strong>Output:&lt;/strong> [[&amp;quot;.Q..&amp;quot;,&amp;quot;&amp;hellip;Q&amp;quot;,&amp;ldquo;Q&amp;hellip;&amp;rdquo;,&amp;quot;..Q.&amp;quot;],[&amp;quot;..Q.&amp;quot;,&amp;ldquo;Q&amp;hellip;&amp;rdquo;,&amp;quot;&amp;hellip;Q&amp;quot;,&amp;quot;.Q..&amp;quot;]] &lt;br>
&lt;strong>Explanation:&lt;/strong> There exist two distinct solutions to the 4-queens puzzle as shown above&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-6">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>&lt;code>@BaseCase&lt;/code> If the current row equals the last row, then we have reached the end of the board and have successfully placed all the queens.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The key idea is to identify that the negative diagonals follow the pattern &lt;code>row-column&lt;/code> and the positive diagonals follow the pattern &lt;code>row+column&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The basic intuition is to place each queen in each row. And then perform a brute-force search to find the correct column in each row.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Maintain three sets for each one of the following:&lt;/p>
&lt;ul>
&lt;li>Column&lt;/li>
&lt;li>Positive Diagonal&lt;/li>
&lt;li>Negative Diagonal&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-11">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def solveNQueens(self, n: int) -&amp;gt; List[List[str]]:
&amp;quot;&amp;quot;&amp;quot;
Although the solution is bruteforce
&amp;quot;&amp;quot;&amp;quot;
board = [[&amp;quot;.&amp;quot;]*n for _ in range(n)]
result = []
col = set()
posDiag = set()
negDiag = set()
def solveByRow(i:int):
if i == n:
solved = [&amp;quot;&amp;quot;.join(row) for row in board]
result.append(solved)
return
for j in range(n):
if j in col or (i-j) in negDiag or (i+j) in posDiag:
continue
col.add(j)
negDiag.add((i-j))
posDiag.add((i+j))
board[i][j] = &amp;quot;Q&amp;quot;
solveByRow(i+1)
board[i][j] = &amp;quot;.&amp;quot;
posDiag.remove((i+j))
negDiag.remove((i-j))
col.remove(j)
solveByRow(0)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="40-combination-sum-ii">40. Combination Sum II&lt;/h3>
&lt;p>Given a collection of candidate numbers (&lt;code>candidates&lt;/code>) and a target number (&lt;code>target&lt;/code>), find all unique combinations in candidates where the candidate numbers sum to &lt;code>target&lt;/code>.&lt;/p>
&lt;p>Each number in &lt;code>candidates&lt;/code> may only be used &lt;strong>once&lt;/strong> in the combination.&lt;/p>
&lt;p>&lt;strong>Note:&lt;/strong> The solution set must not contain duplicate combinations.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> candidates = [10,1,2,7,6,1,5], target = 8 &lt;br>
&lt;strong>Output:&lt;/strong> [[1,1,6], [1,2,5], [1,7], [2,6]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-7">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>Sort the array so that duplicate numbers are next to each other&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>@BaseCase&lt;/code> when the sum of the array is greater than the target.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>@BaseCase&lt;/code> when the sum of the array is equal to the target.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The action is to append a candidate to the current subset and recursive call.&lt;/p>
&lt;ul>
&lt;li>Prune the candidate and recursive call.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>To handle duplicates, we sort the array to ensure duplicates are arranged consecutively.&lt;/p>
&lt;ul>
&lt;li>In the case of pruning, ensure to increment &lt;code>i&lt;/code> till the next element is different.
&lt;ul>
&lt;li>&lt;em>Why?&lt;/em> This ensures that the right subtrees never contain the duplicate element.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-12">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -&amp;gt; List[List[int]]:
result = []
candidates.sort()
def findComb(i:int, comb:List[int], total:int):
if total == target:
result.append(comb.copy())
return
if i &amp;gt;= len(candidates) or total &amp;gt; target:
return
c = candidates[i]
comb.append(c)
findComb(i+1, comb, total+c)
comb.pop()
while i &amp;lt; len(candidates)-1 and candidates[i] == candidates[i+1]:
i += 1
findComb(i+1, comb, total)
findComb(0, [], 0)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="46-permutations">46. Permutations&lt;/h3>
&lt;p>Given an array &lt;code>nums&lt;/code> of distinct integers, return &lt;em>all the possible permutations&lt;/em>. You can return the answer in &lt;strong>any order&lt;/strong>.&lt;/p>
&lt;p>Example 1:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Inputs:&lt;/strong> nums = [1,2,3] &lt;br>
&lt;strong>Outputs:&lt;/strong> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-8">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>It is more of bottom up approach of backtracking
&lt;ul>
&lt;li>Keep spiltting the array into two parts and recursively call the function.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>@BaseCase&lt;/code> When the length of the array is one, return the array as an array.&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-13">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def permute(self, nums: List[int]) -&amp;gt; List[List[int]]:
result = []
if len(nums) == 1:
return [nums.copy()]
for _ in range(len(nums)):
n = nums.pop(0)
perms = self.permute(nums)
for perm in perms:
perm.append(n)
result.extend(perms)
nums.append(n)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>7. Computer networks</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/7.-computer-networks/</link><pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/7.-computer-networks/</guid><description>&lt;h2 id="a-transport-layer-services-and-protocols">A. Transport layer services and protocols&lt;/h2>
&lt;p>The transport layer protocols provide the &lt;strong>logical communication&lt;/strong> between applications/processes running in different hosts.&lt;/p>
&lt;ul>
&lt;li>These protocols run in the end systems and not in the network routers.
&lt;ul>
&lt;li>Sender: Breaks the application messages into &lt;strong>Segments&lt;/strong>; passes it to network layers.
&lt;ul>
&lt;li>The segment is further encapsulated into network-layer packets called &lt;strong>Datagrams&lt;/strong>.
&lt;ul>
&lt;li>The datagram is finally passed to the network router.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Receiver: Receives the segments and &lt;em>re-assembles&lt;/em> the application messages; passes it to application layer.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>There are different transport layer protocols, each with its own characteristics. The following are the most common ones:&lt;/p>
&lt;ul>
&lt;li>Transmission Control Protocol (TCP)&lt;/li>
&lt;li>User Datagram Protocol (UDP)&lt;/li>
&lt;/ul>
&lt;h3 id="user-datagram-protocol-udp">User Datagram Protocol (UDP)&lt;/h3>
&lt;p>&amp;ldquo;No frills,&amp;rdquo; &amp;ldquo;bare bones&amp;rdquo; Internet transport protocol. UDP is a &lt;strong>connectionless&lt;/strong> protocol.&lt;/p>
&lt;p>&lt;strong>Connectionless:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>No handshaking between UDP sender and receiver.&lt;/li>
&lt;li>Each segment is handled independently of others.&lt;/li>
&lt;/ul>
&lt;div class="alert alert-note">
&lt;div>
&lt;p>&lt;strong>Why use UDP?&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>No connection needs to be established which usually creates a delay&lt;/li>
&lt;li>Simple: no connection state at sender and receiver&lt;/li>
&lt;li>Small segment header&lt;/li>
&lt;li>No congestion control: USP can blast away as fast as desired&lt;/li>
&lt;/ul>
&lt;/div>
&lt;/div>
&lt;p>&lt;em>Most often used for streaming multimedia applications.&lt;/em>&lt;/p>
&lt;p>Other uses: Domain name system (DNS), Simple network management protocol (SNMP)&lt;/p>
&lt;p>&lt;strong>Protocol specifications:&lt;/strong>&lt;/p>
&lt;figure id="figure-fig-1-udp-segment-format">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Fig 1. UDP segment format" srcset="
/media/leetcode/UDP_hu8282272e409656a3d57df35588b4ab15_12056_51948e939ee52001b3780080d9916c45.webp 400w,
/media/leetcode/UDP_hu8282272e409656a3d57df35588b4ab15_12056_8a76b668f27ab3675c5d0183bdb73014.webp 760w,
/media/leetcode/UDP_hu8282272e409656a3d57df35588b4ab15_12056_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/UDP_hu8282272e409656a3d57df35588b4ab15_12056_51948e939ee52001b3780080d9916c45.webp"
width="483"
height="295"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Fig 1. UDP segment format
&lt;/figcaption>&lt;/figure>
&lt;p>Few notable ports and protocols:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Port number&lt;/th>
&lt;th>Protocol&lt;/th>
&lt;th>Application&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>53&lt;/td>
&lt;td>&lt;code>UDP&lt;/code>, &lt;code>TCP&lt;/code>&lt;/td>
&lt;td>Domain name system (DNS)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>80&lt;/td>
&lt;td>&lt;code>TCP&lt;/code>&lt;/td>
&lt;td>HTTP (WWW)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>443&lt;/td>
&lt;td>&lt;code>TCP&lt;/code>&lt;/td>
&lt;td>HTTPS (SSL)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>16, 384-32, 767&lt;/td>
&lt;td>&lt;code>UDP&lt;/code>&lt;/td>
&lt;td>Voice and video&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="transmission-control-protocol-tcp">Transmission Control Protocol (TCP)&lt;/h3>
&lt;p>&amp;ldquo;Connection-oriented&amp;rdquo; transport protocol.&lt;/p>
&lt;p>&lt;strong>Properties:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Point-to-point: One sender, one receiver.&lt;/li>
&lt;li>Connection-oriented: Handshaking in it&amp;rsquo;s sender. receiver state before data exchange.&lt;/li>
&lt;li>Full duplex: Bi-directional data flow in same connection
&lt;ul>
&lt;li>MSS: Maximum segment size&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Reliable, in-order byte stream: Segments are sent in order and acknowledged by receiver.&lt;/li>
&lt;li>Flow controlled: Segments are not sent if receiver is not ready.&lt;/li>
&lt;/ul>
&lt;div class="alert alert-note">
&lt;div>
&lt;p>&lt;strong>TCP Segment structure&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Includes both source and destination port numbers, checksum.&lt;/li>
&lt;li>32 bit sequence number, 32 bit acknowledgment number.&lt;/li>
&lt;li>4 bit header length specifies the length of the TCP header in 32-bit words.&lt;/li>
&lt;/ul>
&lt;/div>
&lt;/div></description></item><item><title>8. PEP8 Standards</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/8.-pep8-standards/</link><pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/8.-pep8-standards/</guid><description>&lt;h3 id="imports">&lt;strong>Imports&lt;/strong>&lt;/h3>
&lt;p>Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.&lt;/p>
&lt;p>Imports should be grouped in the following order:&lt;/p>
&lt;ol>
&lt;li>Standard library imports.&lt;/li>
&lt;li>Related third party imports.&lt;/li>
&lt;li>Local application/library specific imports.&lt;/li>
&lt;/ol>
&lt;p>You should put a blank line between each group of imports.&lt;/p>
&lt;h3 id="module-level-dunder-names">&lt;strong>Module Level Dunder Names&lt;/strong>&lt;/h3>
&lt;p>Module level &amp;ldquo;dunders&amp;rdquo; (i.e. names with two leading and two trailing underscores) such as &lt;code>__all__&lt;/code>, &lt;code>__author__&lt;/code>, &lt;code>__version__&lt;/code>, etc. should be placed after the module docstring but before any import statements except from &lt;code>__future__&lt;/code> imports. Python mandates that future-imports must appear in the module before any other code except docstrings:&lt;/p>
&lt;pre>&lt;code class="language-python">&amp;quot;&amp;quot;&amp;quot;This is the example module.
This module does stuff.
&amp;quot;&amp;quot;&amp;quot;
from __future__ import barry_as_FLUFL
__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
&lt;/code>&lt;/pre>
&lt;h3 id="naming-conventions">&lt;strong>Naming Conventions&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>b (single lowercase letter)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>B (single uppercase letter)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>lowercase&lt;/p>
&lt;/li>
&lt;li>
&lt;p>lower_case_with_underscores&lt;/p>
&lt;/li>
&lt;li>
&lt;p>UPPERCASE&lt;/p>
&lt;/li>
&lt;li>
&lt;p>UPPER_CASE_WITH_UNDERSCORES&lt;/p>
&lt;/li>
&lt;li>
&lt;p>CapitalizedWords (or CapWords, or CamelCase &amp;ndash; so named because of the bumpy look of its letters [4]). This is also sometimes known as StudlyCaps.&lt;/p>
&lt;p>Note: When using acronyms in CapWords, capitalize all the letters of the acronym. Thus HTTPServerError is better than HttpServerError.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>mixedCase (differs from CapitalizedWords by initial lowercase character!)
Capitalized_Words_With_Underscores (ugly!)&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>In addition, the following special forms using leading or trailing underscores are recognized (these can generally be combined with any case convention):&lt;/p>
&lt;p>_single_leading_underscore: weak &amp;ldquo;internal use&amp;rdquo; indicator. E.g. from M import * &lt;strong>does not import objects whose names start with an underscore.&lt;/strong>&lt;/p>
&lt;p>&lt;code>_single_trailing_underscore&lt;/code>: used by convention to avoid conflicts with Python keyword, e.g.&lt;/p>
&lt;pre>&lt;code class="language-python">tkinter.Toplevel(master, class_='ClassName')
&lt;/code>&lt;/pre>
&lt;p>&lt;code>__double_leading_underscore&lt;/code>: when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes FooBar__boo; see below).&lt;/p>
&lt;p>&lt;strong>__double_leading_and_trailing_underscore__&lt;/strong>: &amp;ldquo;magic&amp;rdquo; objects or attributes that live in user-controlled namespaces. E.g. &lt;strong>init&lt;/strong>, &lt;strong>import&lt;/strong> or &lt;strong>file&lt;/strong>. Never invent such names; only use them as documented.&lt;/p>
&lt;h3 id="misc">&lt;strong>Misc&lt;/strong>&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Trailing commas are usually optional, except they are mandatory when making a tuple of one element (and in Python 2 they have semantics for the print statement). For clarity, it is recommended to surround the latter in (technically redundant) parentheses:&lt;/p>
&lt;pre>&lt;code class="language-python"># Correct:
FILES = ('setup.cfg',)
# Wrong:
FILES = 'setup.cfg',
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ul></description></item><item><title>9. Object oriented programming</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/9.-object-oriented-programming-oop/</link><pubDate>Thu, 18 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/9.-object-oriented-programming-oop/</guid><description>&lt;h3 id="a-what-is-oop">A. What is OOP?&lt;/h3>
&lt;p>Object oriented programming (OOP) is a programming paradigm that relies on the concept of &lt;em>classes&lt;/em> and &lt;em>objects&lt;/em>. The key idea is to structure the program into reusable pieces of code, which are used to create individual instances.&lt;/p>
&lt;ul>
&lt;li>&lt;em>Class:&lt;/em> An abstract blueprint used to create more specific, concrete objects.
&lt;ul>
&lt;li>They have shared attributes&lt;/li>
&lt;li>classes can also contain functions called &lt;strong>methods&lt;/strong>, available only to objects of that class&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;em>Object:&lt;/em> An instance of a class.&lt;/li>
&lt;/ul>
&lt;h3 id="b-why-use-oop">B. Why use OOP?&lt;/h3>
&lt;ol>
&lt;li>Models complex things as reproducible, simple structures.&lt;/li>
&lt;li>Reusable.&lt;/li>
&lt;li>Secure, protects information through encapsulation.&lt;/li>
&lt;/ol>
&lt;h3 id="c-four-principles-of-oop">C. Four principles of OOP&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>Abstraction:&lt;/strong> Exposing only high level public methods for accessing an object.&lt;/li>
&lt;li>&lt;strong>Encapsulation:&lt;/strong> Hiding implementation details from the user and exposing only selected information.&lt;/li>
&lt;li>&lt;strong>Inheritance:&lt;/strong> Child classes inherit data and behaviours from parent class.&lt;/li>
&lt;li>&lt;strong>Polymorphism:&lt;/strong> Designing objects to share behaviours. Polymorphism allows the same method to behave differently depending on the type of object.
&lt;ul>
&lt;li>&lt;em>Method overriding:&lt;/em> A child class can provide a different implementation than its parent class.&lt;/li>
&lt;li>&lt;em>Method overloading:&lt;/em> Methods or functions can have same name, but different number and type of parameters.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="d-other-concepts">D. Other concepts&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>virtual functions:&lt;/strong> Functions that are present in the parent class and are overridden by the subclass.&lt;/li>
&lt;li>&lt;strong>Constructor:&lt;/strong> A special type of method that has the same name as the class and is used to initialize objects of that class.&lt;/li>
&lt;/ul></description></item><item><title>10. Miscelleaneous problems</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/10.-misc-problems/</link><pubDate>Thu, 18 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/10.-misc-problems/</guid><description>&lt;h3 id="1007-minimum-domino-rotations-for-equal-row">1007. Minimum Domino Rotations For Equal Row&lt;/h3>
&lt;p>In a row of dominoes, &lt;code>tops[i]&lt;/code> and &lt;code>bottoms[i]&lt;/code> represent the top and bottom halves of the &lt;code>ith&lt;/code> domino. (A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.)&lt;/p>
&lt;p>We may rotate the &lt;code>ith&lt;/code> domino, so that tops[i] and bottoms[i] swap values.&lt;/p>
&lt;p>Return the minimum number of rotations so that all the values in tops are the same, or all the values in bottoms are the same.&lt;/p>
&lt;p>If it cannot be done, return -1.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsminimum-domino-rotations-for-equal-row">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/minimum-domino-rotations-for-equal-row/" srcset="
/media/leetcode/domino_hubca40ba0dd65308282bb1cf613af7bfa_17968_4a1c6ef2ede29c246d653c5a6c205587.webp 400w,
/media/leetcode/domino_hubca40ba0dd65308282bb1cf613af7bfa_17968_cb887c084e0ba5ee84f3951445db3a66.webp 760w,
/media/leetcode/domino_hubca40ba0dd65308282bb1cf613af7bfa_17968_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/domino_hubca40ba0dd65308282bb1cf613af7bfa_17968_4a1c6ef2ede29c246d653c5a6c205587.webp"
width="500px"
height="477"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/minimum-domino-rotations-for-equal-row/">https://leetcode.com/problems/minimum-domino-rotations-for-equal-row/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> tops = [2,1,2,4,2,2], bottoms = [5,2,6,2,3,2] &amp;gt; &lt;strong>Output:&lt;/strong> 2
&lt;strong>Explanation:&lt;/strong>
The first figure represents the dominoes as given by tops and bottoms: before we do any rotations. &lt;br>
If we rotate the second and fourth dominoes, we can make every value in the top row equal to 2, as indicated by the second figure.&lt;/p>
&lt;/blockquote>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">from collections import Counter
class Solution:
def minDominoRotations(self, tops: List[int], bottoms: List[int]) -&amp;gt; int:
def minRotationWithRef(arr: List[int], swap:List[int]) -&amp;gt; int:
&amp;quot;&amp;quot;&amp;quot;Returns a minimum rotations to normalize arr&amp;quot;&amp;quot;&amp;quot;
arrCount = Counter(tops)
arrCount = dict(sorted(arrCount.items(), key=lambda x:x[1], reverse=True))
minTurns = float(&amp;quot;inf&amp;quot;)
for ref, v in arrCount.items():
turns = 0
for i in range(len(arr)):
if arr[i] == ref:
continue
if arr[i] != ref and swap[i] != ref:
break
turns += 1
if i == len(arr)-1:
minTurns = min(minTurns, turns)
return minTurns
minRotateTops = minRotationWithRef(tops, bottoms)
minRotateBottom = minRotationWithRef(bottoms, tops)
ans = min(minRotateTops, minRotateBottom)
if ans == float(&amp;quot;inf&amp;quot;):
return -1
return ans
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>11. Design principles and patterns</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/11.-design-principles-and-patterns/</link><pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/11.-design-principles-and-patterns/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-solid-principles">A. SOLID principles&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;li>&lt;a href="#a1-achieve-low-coupling">A1. Achieve Low Coupling&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#b-technical-debt">B. Technical Debt&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#b1-how-to-tackle-technical-debt">B1. How to tackle technical debt&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-solid-principles">A. SOLID principles&lt;/h2>
&lt;p>A mnemonic for 5 design principles of object-oriented programs.&lt;/p>
&lt;figure id="figure-image-from-freecodecamp">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from freeCodeCamp" srcset="
/media/leetcode/solid_hub7dacf183b644b9ab031a4a05edf5890_187227_b1a5aee61ebc0becc37e174ac1c4bac7.webp 400w,
/media/leetcode/solid_hub7dacf183b644b9ab031a4a05edf5890_187227_17236fb60391ca6b5addfead0e841635.webp 760w,
/media/leetcode/solid_hub7dacf183b644b9ab031a4a05edf5890_187227_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/solid_hub7dacf183b644b9ab031a4a05edf5890_187227_b1a5aee61ebc0becc37e174ac1c4bac7.webp"
width="760"
height="350"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from freeCodeCamp
&lt;/figcaption>&lt;/figure>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Single responsibility principle (SRP):&lt;/strong> A class, module, or function in a program should do only one job.&lt;/p>
&lt;ul>
&lt;li>If a single functionality breaks, you know where the bug will be in the code and can trust that only that class will break.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Open-closed principle (OCP):&lt;/strong> A program should be open for extension, but closed for modification.&lt;/p>
&lt;ul>
&lt;li>create entities that can be widely adapted but also remain unchanged.
&lt;ul>
&lt;li>creating duplicate entities with specialized behavior through polymorphism.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Liskov substitution principle (LSP):&lt;/strong> Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.&lt;/p>
&lt;ul>
&lt;li>In simpler words, any class must be directly replaceable by any of its subclasses without error.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Interface segregation principle (ISP):&lt;/strong> Many client-specific interfaces are better than one general-purpose interface.&lt;/p>
&lt;blockquote>
&lt;p>Any unused part of the method should be removed or split into a separate method.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Dependency inversion principle (DIP):&lt;/strong> One should depend upon abstractions, [not] concretions.&lt;/p>
&lt;ul>
&lt;li>High level modules should not depend upon low level modules. Both should depend upon abstractions.&lt;/li>
&lt;li>Abstractions should not depend on details. Details should depend on abstractions.
&lt;blockquote>
&lt;p>If you minimize dependencies, changes will be more localized and require less work to find all affected components.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;ul>
&lt;li>DIP decouples high and low-level components and instead connects both to abstractions.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h4 id="summary">Summary&lt;/h4>
&lt;figure id="figure-image-from-devopedia">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from devopedia" srcset="
/media/leetcode/8101.1558682601_hu8790b876de2ecd17d1381723e80548d8_50312_8be912627143fb5a36fb36dc41ecf5e1.webp 400w,
/media/leetcode/8101.1558682601_hu8790b876de2ecd17d1381723e80548d8_50312_7f185c8cf70ea9785bc9b7d1fee07107.webp 760w,
/media/leetcode/8101.1558682601_hu8790b876de2ecd17d1381723e80548d8_50312_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/8101.1558682601_hu8790b876de2ecd17d1381723e80548d8_50312_8be912627143fb5a36fb36dc41ecf5e1.webp"
width="552"
height="714"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from devopedia
&lt;/figcaption>&lt;/figure>
&lt;h3 id="a1-achieve-low-coupling">A1. Achieve Low Coupling&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>Avoid deep inheritance&lt;/p>
&lt;ul>
&lt;li>Seperate creating resources from using them&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Introduce abstractions&lt;/p>
&lt;ul>
&lt;li>Use interfaces and abstract classes&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Avoid inappropriately intimacy&lt;/p>
&lt;ul>
&lt;li>What is it? Getting a lot more data than the required data.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Introduce an intermediate data structure&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="b-technical-debt">B. Technical Debt&lt;/h2>
&lt;p>Often technical debt refers to a rushed development process or a lack of shared knowledge among team members. Sometimes it is inevitable.&lt;/p>
&lt;ol>
&lt;li>Knowledge based debt&lt;/li>
&lt;li>Design based debt&lt;/li>
&lt;li>Code based debt&lt;/li>
&lt;/ol>
&lt;h3 id="b1-how-to-tackle-technical-debt">B1. How to tackle technical debt&lt;/h3>
&lt;ol>
&lt;li>Code and architecture refactoring - Resolve code and design debt is organising a refactoring week every X sprints&lt;/li>
&lt;li>Start regular technical debt discussions&lt;/li>
&lt;li>Start tracking technical debt in your editor
&lt;ul>
&lt;li>Documentation&lt;/li>
&lt;li>Code comments&lt;/li>
&lt;li>JIRA tickets (backlogs)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol></description></item><item><title>12. Arrays &amp; Hashing</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/12.-arrays-hashing/</link><pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/12.-arrays-hashing/</guid><description>&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;div class="alert alert-note">
&lt;div>
&lt;p>Set is implemented as a hash table in python.&lt;/p>
&lt;p>&lt;strong>Average case:&lt;/strong> Lookup/insert/delete = O(1)&lt;/p>
&lt;p>&lt;strong>Worst case:&lt;/strong> Lookup/insert/delete = O(n); due to hash collision&lt;/p>
&lt;/div>
&lt;/div>
&lt;h2 id="b-leetcode-problems">B. Leetcode problems&lt;/h2>
&lt;h3 id="128-longest-consecutive-sequence">128. Longest Consecutive Sequence&lt;/h3>
&lt;p>Given an unsorted array of integers &lt;code>nums&lt;/code>, return the length of the longest consecutive elements sequence.&lt;/p>
&lt;p>You must write an algorithm that runs in &lt;code>O(n)&lt;/code> time.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [100,4,200,1,3,2] &lt;br>
&lt;strong>Output:&lt;/strong> 4
&lt;strong>Explanation:&lt;/strong> The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>What determines a sequence is the start and end, so create a set and check if the &lt;code>num-1&lt;/code> exists in the set
&lt;ul>
&lt;li>If it does not exist, then it is the start of a sequence
&lt;ul>
&lt;li>iteratively increase the length of the sequence till the num is not in the set&lt;/li>
&lt;li>check max length&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">class Solution:
def longestConsecutive(self, nums: List[int]) -&amp;gt; int:
if not nums:
return 0
history = set(nums)
maxlen = float(&amp;quot;-inf&amp;quot;)
for num in nums:
if num-1 not in history:
# start of a sequence
length = 0
while (num+length) in history:
length += 1
maxlen = max(maxlen, length)
return maxlen
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="1-two-sum">1. Two Sum&lt;/h3>
&lt;p>Given an array of integers &lt;code>nums&lt;/code> and an integer &lt;code>target&lt;/code>, return &lt;em>indices of the two numbers such that they add up to target.&lt;/em>&lt;/p>
&lt;p>You may assume that each input would have &lt;strong>exactly one solution&lt;/strong>, and you may not use the &lt;em>same element twice.&lt;/em>&lt;/p>
&lt;p>You can return the answer in any order.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [2, 7, 11, 15], target = 9 &lt;br>
&lt;strong>Output:&lt;/strong> [0, 1] &lt;br>
&lt;strong>Explanation:&lt;/strong> Because nums[0] + nums[1] == 9, we return [0, 1].&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas:&lt;/h4>
&lt;ul>
&lt;li>Use a hash table to store the number and its index&lt;/li>
&lt;li>Iterate through the array and check if the number is in the hash table
&lt;ul>
&lt;li>If it is, return the index pair&lt;/li>
&lt;li>If it is not, then add the difference between the number and target to the hash table with the index&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def twoSum(self, nums: List[int], target: int) -&amp;gt; List[int]:
hashmap = {}
for i, val in enumerate(nums):
if val in hashmap:
return [hashmap[val], i]
hashmap[target-val] = i
return -1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>13. Sliding Window</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/13.-sliding-window/</link><pubDate>Wed, 24 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/13.-sliding-window/</guid><description>&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;h4 id="i-what-is-it">I. What is it?&lt;/h4>
&lt;p>A powerful algorithmic mental model.&lt;/p>
&lt;ul>
&lt;li>Usually involves &lt;strong>iterable/sequential&lt;/strong> data structures.
&lt;ul>
&lt;li>&lt;strong>contiguous&lt;/strong> sequence of elements&lt;/li>
&lt;li>strings, arrays, linked lists, etc.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;em>Goal:&lt;/em> Min, Max, Longest, Shortest, Contained
&lt;ul>
&lt;li>Calculating somthing: Average, sum, etc.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="ii-lets-meet-the-variants">II. Lets meet the variants&lt;/h4>
&lt;figure id="figure-some-variants-of-the-problem">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Some variants of the &amp;#39;problem&amp;#39;" srcset="
/media/leetcode/variants_hu0dc65328051601190d297f85bf4a92f6_320213_4fcc349967a2be5f1627d1b17f9a3832.webp 400w,
/media/leetcode/variants_hu0dc65328051601190d297f85bf4a92f6_320213_a845682092d33aa9cd162e3409f09c5c.webp 760w,
/media/leetcode/variants_hu0dc65328051601190d297f85bf4a92f6_320213_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/variants_hu0dc65328051601190d297f85bf4a92f6_320213_4fcc349967a2be5f1627d1b17f9a3832.webp"
width="600px"
height="319"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Some variants of the &amp;lsquo;problem&amp;rsquo;
&lt;/figcaption>&lt;/figure>
&lt;ol>
&lt;li>
&lt;p>Fixed length variant&lt;/p>
&lt;ul>
&lt;li>max sum of subarray of size k&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Dynamic variant&lt;/p>
&lt;ul>
&lt;li>smallest sum that is greater than or equal to a target&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Dynamic variant w/ Auxillary data structure (hashmap, set, etc.)&lt;/p>
&lt;ul>
&lt;li>longest substring with at most k distinct characters&lt;/li>
&lt;li>string permutation&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>&lt;em>Commonalities:&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Everything is grouped in a sequence&lt;/li>
&lt;/ul>
&lt;h2 id="b-leetcode-problems">B. Leetcode problems&lt;/h2>
&lt;h3 id="121-best-time-to-buy-and-sell-stock">121. Best Time to Buy and Sell Stock&lt;/h3>
&lt;p>You are given an array &lt;code>prices&lt;/code> where &lt;code>prices[i]&lt;/code> is the price of a given stock on the &lt;code>ith&lt;/code> day.&lt;/p>
&lt;p>You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.&lt;/p>
&lt;p>Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return &lt;code>0&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> prices = [7,1,5,3,6,4] &lt;br>
&lt;strong>Output:&lt;/strong> 5 &lt;br>
&lt;strong>Explanation:&lt;/strong> Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. &lt;br>
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>The auxillary data structure is a &lt;code>min_price&lt;/code> variable
&lt;ul>
&lt;li>We keep track of the minimum price we have seen so far&lt;/li>
&lt;li>We can use this to calculate the maximum profit we can make&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def maxProfit(self, prices: List[int]) -&amp;gt; int:
profit = 0
minBuy = prices[0]
for sellP in prices:
profit = max(profit, sellP-minBuy)
minBuy = min(minBuy, sellP)
return profit
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="3-longest-substring-without-repeating-characters">3. Longest Substring Without Repeating Characters&lt;/h3>
&lt;p>Given a string &lt;code>s&lt;/code>, find the length of the longest substring without repeating characters.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> s = &amp;ldquo;abcabcbb&amp;rdquo;
&lt;strong>Output:&lt;/strong> 3
&lt;strong>Explanation:&lt;/strong> The answer is &amp;ldquo;abc&amp;rdquo;, with the length of 3.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>Move the forward pointer of the window with the outer &lt;code>for&lt;/code> loop
&lt;ul>
&lt;li>Maintain a &lt;code>set&lt;/code> of the characters in the window&lt;/li>
&lt;li>At any point, keep removing the character at the beginning of the window until the window is valid
&lt;ul>
&lt;li>Increment the window size by 1 for each removal&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Keep track of the maximum length of the substring&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def lengthOfLongestSubstring(self, s: str) -&amp;gt; int:
if len(s) == 0:
return 0
start = 0
seen = set()
maxlen = 1
for i in range(len(s)):
while s[i] in seen:
seen.remove(s[start])
start += 1
seen.add(s[i])
maxlen = max(maxlen, len(seen))
return maxlen
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="567-permutation-in-string">567. Permutation in String&lt;/h3>
&lt;p>Given two strings &lt;code>s1&lt;/code> and &lt;code>s2&lt;/code>, return &lt;code>true&lt;/code> if &lt;code>s2&lt;/code> contains a permutation of &lt;code>s1&lt;/code>, or &lt;code>false&lt;/code> otherwise.&lt;/p>
&lt;p>In other words, return &lt;code>true&lt;/code> if one of &lt;code>s1&lt;/code>&amp;rsquo;s permutations is the substring of &lt;code>s2&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> s1=&amp;ldquo;ab&amp;rdquo; s2=&amp;ldquo;eidbaooo&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> true
&lt;strong>Explanation:&lt;/strong> s2 contains one permutation of s1 (&amp;ldquo;ba&amp;rdquo;).&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-2">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>Checking permutation of one string in another is essentially checking the anagram in the window
&lt;ul>
&lt;li>run a loop while the right pointer is less than the length of &lt;code>s2&lt;/code>
&lt;ul>
&lt;li>Use a hashmap to keep track of the characters in the window&lt;/li>
&lt;/ul>
&lt;ul>
&lt;li>If it is equal to the hashmap of &lt;code>s1&lt;/code>, return &lt;code>true&lt;/code>&lt;/li>
&lt;li>Increment both right and left pointers by 1&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-3">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
from collections import Counter
class Solution:
def checkInclusion(self, s1: str, s2: str) -&amp;gt; bool:
if len(s1) &amp;gt; len(s2):
return False
l = 0
r = len(s1)
s1Count = Counter(s1)
while r &amp;lt;= len(s2):
if s1Count == Counter(s2[l:r]):
return True
l += 1
r += 1
return False
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="76-minimum-window-substring">76. Minimum Window Substring&lt;/h3>
&lt;p>Given two strings &lt;code>s&lt;/code> and &lt;code>t&lt;/code> of lengths &lt;code>m&lt;/code> and &lt;code>n&lt;/code> respectively, return the minimum window substring of &lt;code>s&lt;/code> such that every character in &lt;code>t&lt;/code> (including duplicates) is included in the window. If there is no such substring, return the empty string &lt;code>&amp;quot;&amp;quot;&lt;/code>.&lt;/p>
&lt;p>The testcases will be generated such that the answer is &lt;strong>unique&lt;/strong>.&lt;/p>
&lt;p>A &lt;strong>substring&lt;/strong> is a contiguous sequence of characters within the string.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> s = &amp;ldquo;ADOBECODEBANC&amp;rdquo;, t = &amp;ldquo;ABC&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> &amp;ldquo;BANC&amp;rdquo;
&lt;strong>Explanation:&lt;/strong> The minimum window substring &amp;ldquo;BANC&amp;rdquo; includes &amp;lsquo;A&amp;rsquo;, &amp;lsquo;B&amp;rsquo;, and &amp;lsquo;C&amp;rsquo; from string t.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-3">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>create a hashmap of the characters in &lt;code>t&lt;/code> which are the &lt;em>expected characters&lt;/em> in a window.&lt;/li>
&lt;li>Use a hashmap to keep track of the characters in the window
&lt;ul>
&lt;li>use &lt;code>left&lt;/code> and &lt;code>right&lt;/code> pointers to handle the length of window&lt;/li>
&lt;li>use &lt;code>seen&lt;/code> to keep track of the &lt;em>expected characters&lt;/em> in the window
&lt;ul>
&lt;li>if &lt;code>seen&lt;/code> is equal to the length of hashmap of &lt;code>t&lt;/code> then start moving the left pointer&lt;/li>
&lt;li>maintain the minimum length of the window and its string&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-4">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def minWindow(self, s: str, t: str) -&amp;gt; str:
m,n = len(s), len(t)
if n == 0:
return &amp;quot;&amp;quot;
refCharCount = dict(collections.Counter(t))
expectedKeyChars = len(refCharCount)
seen = 0
windowMap = {} # contains the character count in the current window
l = 0
minMatch, minlen = [0,0], float(&amp;quot;inf&amp;quot;)
for r in range(m):
c = s[r]
windowMap[c] = windowMap.get(c, 0) + 1
if c in refCharCount and windowMap[c] == refCharCount[c]:
seen += 1
while l &amp;lt;= r and seen == expectedKeyChars:
if minlen &amp;gt; r-l+1:
minMatch = s[l:r+1]
minlen = min(minlen, r-l+1)
windowMap[s[l]] -= 1
# reduce seen if the removed character is in refCharCount
if s[l] in refCharCount and windowMap[s[l]] &amp;lt; refCharCount[s[l]]:
seen -= 1
l += 1
if minlen == float(&amp;quot;inf&amp;quot;):
return &amp;quot;&amp;quot;
return minMatch
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="239-sliding-window-maximum">239. Sliding Window Maximum&lt;/h3>
&lt;p>You are given an array of integers &lt;code>nums&lt;/code>, there is a sliding window of size &lt;code>k&lt;/code> which is moving from the very left of the array to the very right. You can only see the &lt;code>k&lt;/code> numbers in the window. Each time the sliding window moves right by one position.&lt;/p>
&lt;p>Return the &lt;em>max sliding window.&lt;/em>&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [1,3,-1,-3,5,3,6,7], k = 3 &lt;br>
&lt;strong>Output:&lt;/strong> [3,3,5,5,6,7]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-4">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>Maintain a &lt;strong>queue which monotonically decreasing&lt;/strong>; first element is always the maximum&lt;/p>
&lt;ul>
&lt;li>Before adding the element, keep popping till the element is greater than the current number to be added
&lt;ul>
&lt;li>Add the index of the element to the queue&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>If the first element is out of the window, remove it&lt;/li>
&lt;li>If the right index is greater than &lt;code>k-1&lt;/code>, append the first element of the queue to the result
&lt;ul>
&lt;li>Increment the left index by 1&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;code>deque&lt;/code> was used as &lt;code>popleft&lt;/code> and &lt;code>pop&lt;/code> are &lt;code>O(1)&lt;/code> operations&lt;/p>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-5">
&lt;summary>code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -&amp;gt; List[int]:
result = []
l = 0
q = collections.deque([])
for r in range(len(nums)):
while q and nums[q[-1]] &amp;lt; nums[r]:
q.pop()
q.append(r)
if l &amp;gt; q[0]:
q.popleft()
if r &amp;gt;= k-1:
result.append(nums[q[0]])
l+=1
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="424-longest-repeating-character-replacement">424. Longest Repeating Character Replacement&lt;/h3>
&lt;p>You are given a string &lt;code>s&lt;/code> and an integer &lt;code>k&lt;/code>. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most &lt;code>k&lt;/code> times.&lt;/p>
&lt;p>Return the &lt;em>length of the longest substring containing the same letter you can get after performing the above operations.&lt;/em>&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> s = &amp;ldquo;ABAB&amp;rdquo;, k = 2 &lt;br>
&lt;strong>Output:&lt;/strong> 4
&lt;strong>Explanation:&lt;/strong> Replace the two &amp;lsquo;A&amp;rsquo;s with two &amp;lsquo;B&amp;rsquo;s or vice versa.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-5">Key ideas:&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>window is maintained with left and right pointers&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Maintain a &lt;code>dict&lt;/code> to keep track of the character count in the window&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Find the most frequent character in the window&lt;/p>
&lt;ul>
&lt;li>If the following condition is satisfied; move the left pointer and reduce the count of that respective character
$$\text{window length} - \text{count of most freq char} \gt k$$&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>check max length of the window and update the result&lt;/p>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-6">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def characterReplacement(self, s: str, k: int) -&amp;gt; int:
freq = collections.defaultdict(int)
l,r = 0,0
result = 0
while r &amp;lt; len(s):
freq[s[r]] += 1
maxfreq = max(freq.values())
if r-l+1 - maxfreq &amp;gt; k:
freq[s[l]] -= 1
l += 1
result = max(result, r-l+1)
r += 1
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>14. Databases</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/14.-databases/</link><pubDate>Thu, 25 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/14.-databases/</guid><description>&lt;p>&lt;em>Database&lt;/em> refers to logical grouping of data that can support the electronic storage and manipulation of data from a computer system.&lt;/p>
&lt;ul>
&lt;li>Typically controlled by a &lt;strong>database management system (DBMS)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/media/leetcode/relationalnonrelational_huce7c1d975c2a4ccb0c64ba0b8ea0eb22_88045_dcbab11f61b15e5fab544d075fe767d4.webp 400w,
/media/leetcode/relationalnonrelational_huce7c1d975c2a4ccb0c64ba0b8ea0eb22_88045_87b6622863592e9e9464a0a97d2c6976.webp 760w,
/media/leetcode/relationalnonrelational_huce7c1d975c2a4ccb0c64ba0b8ea0eb22_88045_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/relationalnonrelational_huce7c1d975c2a4ccb0c64ba0b8ea0eb22_88045_dcbab11f61b15e5fab544d075fe767d4.webp"
width="500px"
height="512"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;p>Over past five decades, databases have evolved from flat file-based types to innovative relational and non-relational databases. Historically, databases have categorized into four groups:&lt;/p>
&lt;ol>
&lt;li>Flat file-based
&lt;ul>
&lt;li>Consists of file systems with data maintained in files.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Heirarchical file-based database
&lt;ul>
&lt;li>Similar to a flat file-based system but the files share a parent-child relationship.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Relational databases
&lt;ul>
&lt;li>Manage data into tables&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Non-relational databases
&lt;ul>
&lt;li>Customized databases&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h2 id="a-relational-databases">A. Relational Databases&lt;/h2>
&lt;p>(aka) &lt;em>relational database management system (RDMB)&lt;/em>, stores data in tables.&lt;/p>
&lt;p>Tables use columns to hep define the information being stored and rows that hold actual data.&lt;/p>
&lt;ul>
&lt;li>Contains atleast column with unique values and that acts as the &lt;code>primary key&lt;/code>
&lt;ul>
&lt;li>When a table’s primary key is used in a different table, the column in the second table is called a &lt;code>foreign key&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;code>SQL&lt;/code> - Structured query language is used to interact with relational databases. It is a standard language for relational database management systems and supports data retrival, query, and manipulation.&lt;/p>
&lt;p>&lt;strong>Examples:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>MySQL&lt;/li>
&lt;li>Oracle&lt;/li>
&lt;li>Microsoft SQL Server&lt;/li>
&lt;li>PostgreSQL&lt;/li>
&lt;li>MariaDB&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Advantages&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Data accuracy - usage of primary and foreign keys help connect and identify databases&lt;/li>
&lt;li>Simplified model&lt;/li>
&lt;li>Easy access to data&lt;/li>
&lt;li>Normalization&lt;/li>
&lt;/ol>
&lt;h3 id="i-when-to-use-a-relational-database">I. When to use a relational database&lt;/h3>
&lt;ul>
&lt;li>Preferred option for house data that contains a &lt;u>&lt;b>fairly strong structure&lt;/b>&lt;/u> with rows and columns&lt;/li>
&lt;li>Prime candidates - Include data points with a &lt;strong>consistent meaning&lt;/strong> that can be placed into categories and that have relationships&lt;/li>
&lt;li>Better choice in scenarios in which &lt;u>&lt;b>repeated data analysis&lt;/b>&lt;/u> will result in a need to constantly query specific data cross sections.&lt;/li>
&lt;/ul>
&lt;h2 id="b-non-relational-databases">B. Non-relational Databases&lt;/h2>
&lt;p>Non-relational databases contain data stored in a non-tabular format and commonly use data structures such as documents or objects.&lt;/p>
&lt;p>Two most common types of non-relational databases are:&lt;/p>
&lt;ol>
&lt;li>Document-based
&lt;ul>
&lt;li>Stores data in documents&lt;/li>
&lt;li>Supports variety of data types, such as strings, numbers, arrays, and objects&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Key-value
&lt;ul>
&lt;li>Stores data in key-value pairs&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Examples:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>MongoDB&lt;/li>
&lt;li>Amazon DynamoDB&lt;/li>
&lt;li>Redis&lt;/li>
&lt;li>Cassandra&lt;/li>
&lt;li>ETCD&lt;/li>
&lt;li>Google cloud Firestore&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Advantages&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Simple data management&lt;/li>
&lt;li>Greater readability&lt;/li>
&lt;li>Enhanced ability&lt;/li>
&lt;li>Open-source options&lt;/li>
&lt;li>High-performance&lt;/li>
&lt;li>Better scalability&lt;/li>
&lt;/ol>
&lt;h3 id="i-when-to-use-a-non-relational-database">I. When to use a non-relational database&lt;/h3>
&lt;ul>
&lt;li>Suitable for use cases in which there is a large amount of data that relates to a single topic
&lt;ul>
&lt;li>Audience segments&lt;/li>
&lt;li>Unified customer profiles&lt;/li>
&lt;li>Industry-wide trend data&lt;/li>
&lt;li>Application databases&lt;/li>
&lt;li>Large collections of images, text or other data&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>When data that is stored needs to be flixble in terms of size or shape&lt;/li>
&lt;/ul></description></item><item><title>15. Operating systems</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/15.-operating-system/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/15.-operating-system/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-general-hardware">A. General Hardware&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-basics-of-operating-systems">B. Basics of Operating Systems&lt;/a>&lt;/li>
&lt;li>&lt;a href="#c-processes-and-threads">C. Processes and Threads&lt;/a>&lt;/li>
&lt;li>&lt;a href="#d-process-scheduling">D. Process Scheduling&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#processing-states-and-queues">Processing States and Queues&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#e-synchornization">E. Synchornization&lt;/a>&lt;/li>
&lt;li>&lt;a href="#f-memory-management">F. Memory Management&lt;/a>&lt;/li>
&lt;li>&lt;a href="#g-file-systems">G. File Systems&lt;/a>&lt;/li>
&lt;li>&lt;a href="#h-io-systems">H. I/O Systems&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-general-hardware">A. General Hardware&lt;/h2>
&lt;p>&lt;strong>1. Central Processing Unit (CPU)&lt;/strong> - An electronic circuitry that executes instructions based on an input of binary data.&lt;/p>
&lt;p>It consists of three main components:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Control unit (CU)&lt;/p>
&lt;ul>
&lt;li>Control and monitor input and output fo data from computer&amp;rsquo;s hardware&lt;/li>
&lt;li>&lt;strong>Primary job:&lt;/strong> Ensure data is sent to right component, at the right time
&lt;ul>
&lt;li>Ensure all hardware is working on the same schedule&lt;/li>
&lt;li>Does this with a &lt;strong>clock&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Arithmetic and Logic Unit (ALU)&lt;/p>
&lt;ul>
&lt;li>Findamental building block of the CPU, the brains of the entire computer&lt;/li>
&lt;li>Two primary areas
&lt;ul>
&lt;li>&lt;strong>Arithmetic&lt;/strong> - Performs arithmetic operations on data&lt;/li>
&lt;li>&lt;strong>Logic&lt;/strong> - Performs logical operations on data&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Registers (Immediate Access Store)&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Limited space, high-speed memory that CPU can use for quick processing.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Provide CPU with a place to store and access values that are cruicial to immediate calculations the ALU is processing.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Fundamentally, data is just a series of electrical pulses. These pulses run through different components as a means to process and return data.&lt;/p>
&lt;p>&lt;strong>2. Memory&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Random Access Memory (RAM)&lt;/p>
&lt;ul>
&lt;li>Used to store and access information on a short-term basis&lt;/li>
&lt;li>primary volatile memory&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Static Memory (ROM)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Buses&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>It an engineering term for a job-specific high-speed wire.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Groups of wires that transfer electrical signals either in parallel or in series.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Three types of buses&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Data buses - bidirectional; carry data back and forth between processor and other components&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Address buses - unidirectional; carry a specific addresses in memory&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Control buses - unidirectional; carry control signals of CU to other components as well as the clock signals for &lt;em>synchronization&lt;/em>.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="b-basics-of-operating-systems">B. Basics of Operating Systems&lt;/h2>
&lt;p>Take a look at some of the vital functions of an OS:&lt;/p>
&lt;ul>
&lt;li>Process Management&lt;/li>
&lt;li>Memory Management&lt;/li>
&lt;li>File Management&lt;/li>
&lt;li>IO Management&lt;/li>
&lt;li>Multitasking&lt;/li>
&lt;li>Networking&lt;/li>
&lt;li>Security&lt;/li>
&lt;li>Providing a user interface&lt;/li>
&lt;/ul>
&lt;h2 id="c-processes-and-threads">C. Processes and Threads&lt;/h2>
&lt;p>A &lt;strong>process&lt;/strong> is an abstraction within the operating system that represents the program while it is in execution.&lt;/p>
&lt;p>A &lt;strong>thread&lt;/strong> represents the actual sequence of processor instructions that are actively being executed.&lt;/p>
&lt;ul>
&lt;li>Kernel threads are constructed through system calls to the kernel&lt;/li>
&lt;li>User threads are constructed using local function calls.&lt;/li>
&lt;/ul>
&lt;h2 id="d-process-scheduling">D. Process Scheduling&lt;/h2>
&lt;p>Computers have a limited amount of resources, be it processor cores, hard drives, or network links, but the number of tasks that it may need to run are ever-growing.&lt;/p>
&lt;figure id="figure-image-from-codeacademycom">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from codeacademy.com" srcset="
/media/leetcode/os-scheduler-1_hu9ee2c40d7410f6d27b057b570bdc4d3c_51465_5d3003527b813e9323622f56c063e12b.webp 400w,
/media/leetcode/os-scheduler-1_hu9ee2c40d7410f6d27b057b570bdc4d3c_51465_fb86467fbc45095048fffc5beaff3300.webp 760w,
/media/leetcode/os-scheduler-1_hu9ee2c40d7410f6d27b057b570bdc4d3c_51465_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/os-scheduler-1_hu9ee2c40d7410f6d27b057b570bdc4d3c_51465_5d3003527b813e9323622f56c063e12b.webp"
width="1000px"
height="370"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from codeacademy.com
&lt;/figcaption>&lt;/figure>
&lt;h3 id="processing-states-and-queues">Processing States and Queues&lt;/h3>
&lt;p>Processes exist in multiple states in order to best utilize system resources so that if one process is waiting, another can take its place in the CPU.&lt;/p>
&lt;p>&lt;strong>States&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Ready&lt;/li>
&lt;li>Running&lt;/li>
&lt;li>Blocked&lt;/li>
&lt;li>Waiting&lt;/li>
&lt;li>Terminated&lt;/li>
&lt;/ol>
&lt;p>Usually, waiting is done in a queue (FIFO).&lt;/p>
&lt;p>However, the data structure needs to be modified to accommodate the ready queue.&lt;/p>
&lt;p>Different processes may have different priorities, hence a &lt;em>priority queue&lt;/em> becomes the more relevant abstraction.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>priority&lt;/strong> is calculated is determined by the &lt;mark>scheduling algorithm&lt;/mark> and is represented by some integer value or category such as &lt;em>low&lt;/em>, &lt;em>medium&lt;/em>, or &lt;em>high&lt;/em>.&lt;/li>
&lt;/ul>
&lt;h2 id="e-synchornization">E. Synchornization&lt;/h2>
&lt;h2 id="f-memory-management">F. Memory Management&lt;/h2>
&lt;h2 id="g-file-systems">G. File Systems&lt;/h2>
&lt;h2 id="h-io-systems">H. I/O Systems&lt;/h2></description></item><item><title>16. Linked list</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/16.-linked-list/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/16.-linked-list/</guid><description>&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;h2 id="b-leetcode-problems">B. Leetcode Problems&lt;/h2>
&lt;h3 id="146-lru-cache">146. LRU Cache&lt;/h3>
&lt;p>Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.&lt;/p>
&lt;p>Implement the LRUCache class:&lt;/p>
&lt;ul>
&lt;li>&lt;code>LRUCache(int capacity)&lt;/code> Initialize the LRU cache with positive size &lt;code>capacity&lt;/code>.&lt;/li>
&lt;li>&lt;code>int get(int key)&lt;/code> Return the value of the key if the &lt;code>key&lt;/code> exists, otherwise return &lt;code>-1&lt;/code>.&lt;/li>
&lt;li>&lt;code>void put(int key, int value)&lt;/code> Update the value of the &lt;code>key&lt;/code> if the key exists. Otherwise, add the &lt;code>key-value&lt;/code> pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.&lt;/li>
&lt;/ul>
&lt;p>The functions get and put must each run in &lt;code>O(1)&lt;/code> average time complexity.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> &lt;br>
[&amp;ldquo;LRUCache&amp;rdquo;, &amp;ldquo;put&amp;rdquo;, &amp;ldquo;put&amp;rdquo;, &amp;ldquo;get&amp;rdquo;, &amp;ldquo;put&amp;rdquo;, &amp;ldquo;get&amp;rdquo;, &amp;ldquo;put&amp;rdquo;, &amp;ldquo;get&amp;rdquo;, &amp;ldquo;get&amp;rdquo;, &amp;ldquo;get&amp;rdquo;] &lt;br>
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] \&lt;/p>
&lt;p>&lt;strong>Output&lt;/strong> &lt;br>
[null, null, null, 1, null, -1, null, -1, 3, 4]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Use a &lt;strong>hashmap&lt;/strong> to store the key and corresponding &lt;code>node&lt;/code> in the &lt;strong>doubly linked list&lt;/strong>.
&lt;ul>
&lt;li>Use a two pointers &lt;code>left&lt;/code> and &lt;code>right&lt;/code> to point to the head and tail of the doubly linked list.&lt;/li>
&lt;li>&lt;code>left&lt;/code> pointer is the least recently used node, &lt;code>right&lt;/code> pointer is the most recently used node.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>When &lt;code>get&lt;/code> a node, move the node to the &lt;code>right&lt;/code> of the doubly linked list.&lt;/li>
&lt;li>When &lt;code>put&lt;/code> a node, if the node already exists, move the node to the &lt;code>right&lt;/code> of the doubly linked list Otherwise, add the node to the &lt;code>right&lt;/code> of the doubly linked list.&lt;/li>
&lt;li>When the &lt;strong>hashmap&lt;/strong> reaches &lt;code>capacity&lt;/code>, remove the node pointed by the &lt;code>left&lt;/code> pointer.&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-0">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Node:
def __init__(self, k:int, v:int, prv:&amp;quot;Node&amp;quot;=None, nxt:&amp;quot;Node&amp;quot;=None):
self.key = k
self.val = v
self.prev = prv
self.next = nxt
class LRUCache:
def __init__(self, capacity: int):
&amp;quot;&amp;quot;&amp;quot;Initialize a capacity, left and right pointer&amp;quot;&amp;quot;&amp;quot;
self.cap = capacity
self.l = Node(0,0) # Least recently used node
self.r = Node(0,0) # Most recently used node
self.l.next, self.r.prev = self.r, self.l
self.cache = {}
def remove(self, node: Node) -&amp;gt; None:
prv, nxt = node.prev, node.next
prv.next, nxt.prev = nxt, prv
def append(self, node: Node) -&amp;gt; None:
next_node = self.r.prev
next_node.next, node.prev = node, next_node
self.r.prev, node.next = node, self.r
def get(self, key: int) -&amp;gt; int:
if key not in self.cache:
return -1
node = self.cache[key]
val = node.val
self.remove(node)
self.append(node)
return val
def put(self, key: int, value: int) -&amp;gt; None:
if key in self.cache:
self.remove(self.cache[key])
node = Node(key, value)
self.cache[key] = node
self.append(node)
if len(self.cache) &amp;gt; self.cap:
lru_node = self.l.next
self.remove(lru_node)
del self.cache[lru_node.key]
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="2-add-two-numbers">2. Add Two Numbers&lt;/h3>
&lt;p>You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.&lt;/p>
&lt;p>You may assume the two numbers do not contain any leading zero, except the number 0 itself.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemsadd-two-numbers">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/add-two-numbers/" srcset="
/media/leetcode/addtwonumber1_hue7749df343b69c85cdca7ac2f8197243_19627_e48c40bdb37c509b77553b0dd31873f8.webp 400w,
/media/leetcode/addtwonumber1_hue7749df343b69c85cdca7ac2f8197243_19627_9c90b0e46469e96404d2522f98e5c0a0.webp 760w,
/media/leetcode/addtwonumber1_hue7749df343b69c85cdca7ac2f8197243_19627_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/addtwonumber1_hue7749df343b69c85cdca7ac2f8197243_19627_e48c40bdb37c509b77553b0dd31873f8.webp"
width="483"
height="342"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/add-two-numbers/">https://leetcode.com/problems/add-two-numbers/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> l1 = [2,4,3], l2 = [5,6,4] &lt;br>
&lt;strong>Output:&lt;/strong> [7,0,8] &lt;br>
&lt;strong>Explanation:&lt;/strong> 342 + 465 = 807.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Use a &lt;code>dummy&lt;/code> node to store the head of the linked list.&lt;/li>
&lt;li>Use a &lt;code>carry&lt;/code> variable to store the carry of the addition.&lt;/li>
&lt;li>Run the loop till &lt;code>l1&lt;/code> or &lt;code>l2&lt;/code> are not &lt;code>None&lt;/code> or &lt;code>carry&lt;/code> is not &lt;code>0&lt;/code>.&lt;/li>
&lt;li>Add the values of &lt;code>l1&lt;/code> and &lt;code>l2&lt;/code> and &lt;code>carry&lt;/code> and store the sum in &lt;code>sum&lt;/code>.
&lt;ul>
&lt;li>Create a new node with &lt;code>sum % 10&lt;/code> as the value.&lt;/li>
&lt;li>Update the &lt;code>carry&lt;/code> to &lt;code>sum // 10&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -&amp;gt; Optional[ListNode]:
dummy = ListNode()
current = dummy
carry = 0
while l1 or l2 or carry:
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
res = v1+v2+carry
val = res % 10
carry = res//10
current.val = val
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
if l1 or l2 or carry:
current.next = ListNode()
current = current.next
return dummy
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>17. Intervals</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/17.-intervals/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/17.-intervals/</guid><description>&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;h2 id="b-leetcode-problems">B. Leetcode Problems&lt;/h2>
&lt;h3 id="56-merge-intervals">56. Merge Intervals&lt;/h3>
&lt;p>Given an array of &lt;code>intervals&lt;/code> where &lt;code>intervals[i] = [start_i, end_i]&lt;/code>, merge all overlapping intervals, and return &lt;em>an array of the non-overlapping intervals that cover all the intervals in the input.&lt;/em>&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> [[1,3],[2,6],[8,10],[15,18]] &lt;br>
&lt;strong>Output:&lt;/strong> [[1,6],[8,10],[15,18]] &lt;br>
&lt;strong>Explanation:&lt;/strong> Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Sort the intervals by start time&lt;/li>
&lt;li>Iterate through the intervals and check if the current interval overlaps with the previous interval
&lt;ul>
&lt;li>If it does, set the end time of the interval to the max of both end times&lt;/li>
&lt;li>If it does not, add the interval to the result&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-0">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def merge(self, intervals: List[List[int]]) -&amp;gt; List[List[int]]:
intervals.sort(key=lambda x: x[0])
result = [intervals[0]]
for start,end in intervals[1:]:
prev_start, prev_end = result[-1]
if start &amp;lt;= prev_end:
result[-1][1] = max(end, prev_end)
else:
result.append([start, end])
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="919--meeting-rooms-ii">919 · Meeting Rooms II&lt;/h3>
&lt;p>Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],&amp;hellip;] (si &amp;lt; ei), find the minimum number of conference rooms required.)&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> [[0, 30],[5, 10],[15, 20]] &lt;br>
&lt;strong>Output:&lt;/strong> 2
&lt;strong>Explanation:&lt;/strong> &lt;br>
We need two meeting rooms
The first room can only accept the meeting in the time range [0, 30]
The second room can only accept the meeting in the time range [5, 10] and [15, 20]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas&lt;/h4>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
&amp;quot;&amp;quot;&amp;quot;
@param intervals: an array of meeting time intervals
@return: the minimum number of conference rooms required
&amp;quot;&amp;quot;&amp;quot;
def min_meeting_rooms(self, intervals: List[Interval]) -&amp;gt; int:
s,e = 0,0
count = 0
result = float(&amp;quot;-inf&amp;quot;)
starts = [i.start for i in intervals]
ends = [i.end for i in intervals]
starts.sort()
ends.sort()
while s &amp;lt; len(intervals):
if starts[s] &amp;lt; ends[e]:
count += 1
s += 1
result = max(result, count)
else:
e += 1
count -= 1
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>18. Two pointers</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/18.-two-pointers/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/18.-two-pointers/</guid><description>&lt;h2 id="a-general-introduction">A. General Introduction&lt;/h2>
&lt;h2 id="b-leetcode-problems">B. Leetcode Problems&lt;/h2>
&lt;h2 id="1268-search-suggestions-system">1268. Search Suggestions System&lt;/h2>
&lt;p>You are given an array of strings products and a string searchWord.&lt;/p>
&lt;p>Design a system that suggests at most three product names from products after each character of searchWord is typed. Suggested products should have common prefix with searchWord. If there are more than three products with a common prefix return the three lexicographically minimums products.&lt;/p>
&lt;p>Return a list of lists of the suggested products after each character of searchWord is typed.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> products = [&amp;ldquo;mobile&amp;rdquo;,&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;moneypot&amp;rdquo;,&amp;ldquo;monitor&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;], searchWord = &amp;ldquo;mouse&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> [ &lt;br>
    [&amp;ldquo;mobile&amp;rdquo;,&amp;ldquo;moneypot&amp;rdquo;,&amp;ldquo;monitor&amp;rdquo;], &lt;br>
    [&amp;ldquo;mobile&amp;rdquo;,&amp;ldquo;moneypot&amp;rdquo;,&amp;ldquo;monitor&amp;rdquo;], &lt;br>
    [&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;], &lt;br>
    [&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;], &lt;br>
    [&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;] &lt;br>
] &lt;br>
&lt;strong>Explanation:&lt;/strong> products sorted lexicographically = [&amp;ldquo;mobile&amp;rdquo;,&amp;ldquo;moneypot&amp;rdquo;,&amp;ldquo;monitor&amp;rdquo;,&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;] &lt;br>
After typing m and mo all products match and we show user [&amp;ldquo;mobile&amp;rdquo;,&amp;ldquo;moneypot&amp;rdquo;,&amp;ldquo;monitor&amp;rdquo;] &lt;br>
After typing mou, mous and mouse the system suggests [&amp;ldquo;mouse&amp;rdquo;,&amp;ldquo;mousepad&amp;rdquo;]&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Sort the products lexicographically&lt;/li>
&lt;li>Iterate through the &lt;code>searchWord&lt;/code> and move the left and right pointer accordingly if the position of current character index does not match with the position of the character in the product&lt;/li>
&lt;li>Add the first three words within the left and right pointers&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-0">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -&amp;gt; List[List[str]]:
result = []
l, r = 0, len(products)-1
products.sort()
for i, c in enumerate(searchWord):
while l&amp;lt;= r and (len(products[l]) &amp;lt;= i or products[l][i] != c):
l += 1
while l&amp;lt;=r and (len(products[r]) &amp;lt;= i or products[r][i] != c):
r -= 1
out = [p for p in products[l:min(l+3,r+1)]]
result.append(out)
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="28-find-the-index-of-the-first-occurrence-in-a-string">28. Find the Index of the First Occurrence in a String&lt;/h3>
&lt;p>Given two strings &lt;code>needle&lt;/code> and &lt;code>haystack&lt;/code>, return the index of the first occurrence of &lt;code>needle&lt;/code> in &lt;code>haystack&lt;/code>, or &lt;code>-1&lt;/code> if &lt;code>needle&lt;/code> is not part of &lt;code>haystack&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> needle = &amp;ldquo;sad&amp;rdquo;, haystack = &amp;ldquo;sadbutsad&amp;rdquo; &lt;br>
&lt;strong>Output:&lt;/strong> 0
&lt;strong>Explanation:&lt;/strong> The first occurrence of &amp;ldquo;sad&amp;rdquo; is at index 0.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>start&lt;/code> index moves through the string; Have an additional pointer &lt;code>i&lt;/code> to move through the &lt;code>haystack&lt;/code> until character at &lt;code>i&lt;/code> matches the character at index &lt;code>i&lt;/code> of &lt;code>needle&lt;/code>&lt;/li>
&lt;li>If &lt;code>i&lt;/code> equals to the &lt;code>len(needle)-1&lt;/code>, return the &lt;code>start&lt;/code>&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def strStr(self, haystack: str, needle: str) -&amp;gt; int:
if len(needle) &amp;gt; len(haystack):
return -1
start = 0
while start &amp;lt; len(haystack):
idx = 0
while idx &amp;lt; len(needle) and start+idx &amp;lt; len(haystack) and haystack[start+idx] == needle[idx]:
idx += 1
if idx-1 == len(needle)-1:
return start
start += 1
return -1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="15-3sum">15. 3Sum&lt;/h3>
&lt;p>Given an integer array nums, return all the triplets &lt;code>[nums[i], nums[j], nums[k]]&lt;/code> such that &lt;code>i != j&lt;/code>, &lt;code>i != k&lt;/code>, and &lt;code>j != k&lt;/code>, and &lt;code>nums[i] + nums[j] + nums[k] == 0&lt;/code>.&lt;/p>
&lt;p>Notice that the solution set must not contain duplicate triplets.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [-1, 0, 1, 2, -1, -4] &lt;br>
&lt;strong>Output:&lt;/strong> [ &lt;br>
    [-1, 0, 1], &lt;br>
    [-1, -1, 2] &lt;br>
] &lt;br>
&lt;strong>Explanation:&lt;/strong> &lt;br>
nums[0] + nums[1] + nums[2] = 0 &lt;br>
nums[1] + nums[2] + nums[4] = 0 &lt;br>
nums[0] + nums[3] + nums[4] = 0 &lt;br>
The distinct triplets are [-1, 0, 1] and [-1, -1, 2].
Notice that order doesn&amp;rsquo;t matter.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-2">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>To ensure the duplicates have been removed, sort the array; adjacent elements are the same, skip them
&lt;ul>
&lt;li>Iterate through the array and perform &lt;code>twosum&lt;/code> on the remaining array&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def threeSum(self, nums: List[int]) -&amp;gt; List[List[int]]:
idx = 0
result = []
nums.sort()
for idx in range(len(nums)):
if idx &amp;gt; 0 and nums[idx] == nums[idx-1]:
continue
l, r = idx+1, len(nums)-1
while l &amp;lt; r:
threeSum = nums[idx] + nums[l] + nums[r]
if threeSum &amp;gt; 0:
r -= 1
elif threeSum &amp;lt; 0:
l += 1
else:
result.append([nums[idx], nums[l], nums[r]])
l += 1
while l &amp;lt; r and nums[l] == nums[l-1]:
l += 1
return result
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="11-container-with-most-water">11. Container With Most Water&lt;/h3>
&lt;p>You are given an integer array height of length &lt;code>n&lt;/code>. There are &lt;code>n&lt;/code> vertical lines drawn such that the two endpoints of the &lt;code>ith&lt;/code> line are &lt;code>(i, 0)&lt;/code> and &lt;code>(i, height[i])&lt;/code>.&lt;/p>
&lt;p>Find two lines that together with the x-axis form a container, such that the container contains the most water.&lt;/p>
&lt;p>&lt;em>Return the maximum amount of water a container can store.&lt;/em>&lt;/p>
&lt;p>&lt;strong>Notice&lt;/strong> that you may not slant the container.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemscontainer-with-most-water">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/container-with-most-water/" srcset="
/media/leetcode/container_with_most_water_huae5c68289536847dbc2b54f2625c38c0_18362_46d55716899fc59e2310e80e1a8d5dc8.webp 400w,
/media/leetcode/container_with_most_water_huae5c68289536847dbc2b54f2625c38c0_18362_111eedc23e75fe83bf86fb7a7eb8a729.webp 760w,
/media/leetcode/container_with_most_water_huae5c68289536847dbc2b54f2625c38c0_18362_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/container_with_most_water_huae5c68289536847dbc2b54f2625c38c0_18362_46d55716899fc59e2310e80e1a8d5dc8.webp"
width="450px"
height="363"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/container-with-most-water/">https://leetcode.com/problems/container-with-most-water/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;h4 id="key-ideas-3">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>Have two pointers, &lt;code>left&lt;/code> and &lt;code>right&lt;/code> at the beginning and the end of the array
&lt;ul>
&lt;li>The width of the container is always going to decrease, because we move the pointers towards the center&lt;/li>
&lt;li>Hence, we need to maximize the height of the container
&lt;ul>
&lt;li>Move the pointer with the smaller height towards the center&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-4">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def maxArea(self, height: List[int]) -&amp;gt; int:
max_area = float(&amp;quot;-inf&amp;quot;)
l,r = 0, len(height)-1
while l &amp;lt; r:
lh, rh = height[l], height[r]
w = r-l
h = min(lh, rh)
max_area = max(max_area, w*h)
if lh &amp;lt; rh:
l += 1
else:
r -= 1
return max_area
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="42-trapping-rain-water">42. Trapping Rain Water&lt;/h3>
&lt;p>Given &lt;code>n&lt;/code> non-negative integers representing an elevation map where the width of each bar is &lt;code>1&lt;/code>, compute how much water it can trap after raining.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;figure id="figure-image-from-httpsleetcodecomproblemstrapping-rain-water">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Image from https://leetcode.com/problems/trapping-rain-water/" srcset="
/media/leetcode/rainwatertrap_hu9719cee577e08be580e27c92b88994d9_7848_c633747d2bda59a52add6936cbb1b2d4.webp 400w,
/media/leetcode/rainwatertrap_hu9719cee577e08be580e27c92b88994d9_7848_5a0be608ca165d3e6a1d6f336cb4a7df.webp 760w,
/media/leetcode/rainwatertrap_hu9719cee577e08be580e27c92b88994d9_7848_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/rainwatertrap_hu9719cee577e08be580e27c92b88994d9_7848_c633747d2bda59a52add6936cbb1b2d4.webp"
width="550px"
height="161"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Image from &lt;a href="https://leetcode.com/problems/trapping-rain-water/">https://leetcode.com/problems/trapping-rain-water/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;h4 id="key-ideas-4">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>At each index, the following is the amount of water that can be trapped
&lt;ul>
&lt;li>$\text{min}(\text{max_left}, \text{max_right})-\text{height}[i]$&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-6">
&lt;summary>Code - O(1) Space complexity&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def trap(self, height: List[int]) -&amp;gt; int:
m = len(height)
area = 0
leftH = [0]*m
rightH = [0]*m
leftMax = float(&amp;quot;-inf&amp;quot;)
for i in range(1,m):
leftMax = max(height[i-1], leftMax)
leftH[i] = leftMax
rightMax = float(&amp;quot;-inf&amp;quot;)
for i in range(m-2,-1, -1):
rightMax = max(height[i+1], rightMax)
rightH[i] = rightMax
for i in range(m):
a = min(leftH[i], rightH[i]) - height[i]
area += max(0, a)
return area
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>19. Microservices</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/19.-microservices/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/19.-microservices/</guid><description>&lt;h2 id="a-grpc">A. gRPC&lt;/h2>
&lt;p>Microservices are built in different languages and encompass a function of your business. These services need to talk to each other and need to agree on:&lt;/p>
&lt;ul>
&lt;li>API to exchange data&lt;/li>
&lt;li>Data format&lt;/li>
&lt;li>Error patterns&lt;/li>
&lt;li>Load balancing&lt;/li>
&lt;li>etc&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>When developing an API, we need to think of multiple things such as data model, endpoints, invoking and handling errors. In addition, we also need to evaluate efficiency, latency and scalability.&lt;/p>
&lt;h3 id="i-what-is-grpc">I. What is gRPC?&lt;/h3>
&lt;p>&lt;em>Free and open-source framework developed by Google&lt;/em>&lt;/p>
&lt;p>&lt;strong>gRPC&lt;/strong> lets you to define REQUEST and RESPONSE for RPC (remote procedure calls) and handles all the rest.&lt;/p>
&lt;ul>
&lt;li>At the core of gRPC, it lets you define the messages and services using Protocol Buffers&lt;/li>
&lt;li>Brings a great deal of flexibility and convenience to the table&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;pre>&lt;code class="language-proto">syntax = &amp;quot;proto3&amp;quot;;
message Greeting {
string first_name = 1;
}
message GreetRequest {
Greeting greeting = 1;
}
message GreetResponse {
string result = 1;
}
service GreetService {
rpc Greet(GreetRequest) returns (GreetResponse) {}
}
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Why do we use Protocol Buffers?&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Language agnostic&lt;/li>
&lt;li>Code is generated for any language&lt;/li>
&lt;li>Data is binary and efficiently serialized&lt;/li>
&lt;li>Allows for easy API evolution using rules&lt;/li>
&lt;/ul></description></item><item><title>20. Dynamic programming</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/20.-dynamic-programming/</link><pubDate>Sun, 11 Sep 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/20.-dynamic-programming/</guid><description/></item><item><title>21. Deployment strategies</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/21.-deployments/</link><pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/21.-deployments/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-naivebasic-deployment">A. Naive/Basic Deployment&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#b-multi-service-deployment">B. Multi-service Deployment&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#c-rolling-deployment">C. Rolling Deployment&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#d-bluegreen-deployment">D. Blue/Green Deployment&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#e-canary-deployment">E. Canary Deployment&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#f-ab-testing">F. A/B Testing&lt;/a>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-naivebasic-deployment">A. Naive/Basic Deployment&lt;/h2>
&lt;p>All nodes within a target environment are updated at the same time with a new service or artifact version.&lt;/p>
&lt;h4 id="pros">Pros&lt;/h4>
&lt;ul>
&lt;li>Simple, fast, and cheap&lt;/li>
&lt;/ul>
&lt;h4 id="cons">Cons&lt;/h4>
&lt;ul>
&lt;li>Riskiest and does not fall into best practices&lt;/li>
&lt;/ul>
&lt;h2 id="b-multi-service-deployment">B. Multi-service Deployment&lt;/h2>
&lt;p>All nodes within a target environment are updated with multiple new services simultaneously.&lt;/p>
&lt;h4 id="pros-1">Pros&lt;/h4>
&lt;ul>
&lt;li>Simple, fast, cheap, and not as risk-prone as a basic deployment&lt;/li>
&lt;/ul>
&lt;h4 id="cons-1">Cons&lt;/h4>
&lt;ul>
&lt;li>Slow to roll back and not outage-proof&lt;/li>
&lt;/ul>
&lt;h2 id="c-rolling-deployment">C. Rolling Deployment&lt;/h2>
&lt;p>All nodes are incrementally updated with the service version in integer N batches.&lt;/p>
&lt;h4 id="pros-2">Pros&lt;/h4>
&lt;ul>
&lt;li>Relatively simple to roll back, less risky than a basic deployment, and simple to implement&lt;/li>
&lt;/ul>
&lt;h4 id="cons-2">Cons&lt;/h4>
&lt;ul>
&lt;li>Updated in batches, rolling deployments require services to support both new and old versions of the service.&lt;/li>
&lt;/ul>
&lt;h2 id="d-bluegreen-deployment">D. Blue/Green Deployment&lt;/h2>
&lt;ul>
&lt;li>Blue - staging environment&lt;/li>
&lt;li>Green - production environment&lt;/li>
&lt;/ul>
&lt;p>Utilizes two identical environments, with different versions of an application or service. Quality assurance and user acceptance testing are performed in the staging environment.&lt;/p>
&lt;p>User traffic is shifted from the green environment to the blue environment once new changes have been testing and accepted within the blue environment.&lt;/p>
&lt;h4 id="pros-3">Pros&lt;/h4>
&lt;ul>
&lt;li>Simple, fast, well-understood, and easy to implement&lt;/li>
&lt;li>Rollback is straightforward&lt;/li>
&lt;li>Not risky&lt;/li>
&lt;/ul>
&lt;h4 id="cons-3">Cons&lt;/h4>
&lt;ul>
&lt;li>Replicating a production environment can be complex and expensive&lt;/li>
&lt;li>An outage or issue could have a wide-scale business impact before a rollback is triggered&lt;/li>
&lt;/ul>
&lt;h2 id="e-canary-deployment">E. Canary Deployment&lt;/h2>
&lt;p>Release an application incrementally to a subset of users. All infrastructure in a target environment is updated in small phases (2%, 5%, 10%, &amp;hellip;, 100%).&lt;/p>
&lt;h4 id="pros-4">Pros&lt;/h4>
&lt;ul>
&lt;li>Test production with real users&lt;/li>
&lt;li>Fast and safe to trigger a rollback to a previous version of the application&lt;/li>
&lt;/ul>
&lt;h4 id="cons-4">Cons&lt;/h4>
&lt;ul>
&lt;li>Scripting a canary release can be complex: manual verification or testing can take time, and the required monitoring and instrumentation for testing production may involve additional research.&lt;/li>
&lt;/ul>
&lt;h2 id="f-ab-testing">F. A/B Testing&lt;/h2>
&lt;p>Different versions of the same service run simultaneously as &amp;ldquo;experiments&amp;rdquo; in the same environment for a period of time.&lt;/p>
&lt;ul>
&lt;li>Experiments are controls by some mechanism&lt;/li>
&lt;li>Commonly, user traffic is routed based on specific rules or user demographics to perform measurements and comparisons&lt;/li>
&lt;li>Primarly focused on experimentation and exploration&lt;/li>
&lt;/ul>
&lt;h4 id="pros-5">Pros&lt;/h4>
&lt;ul>
&lt;li>Standard, easy and cheap method&lt;/li>
&lt;/ul>
&lt;h4 id="cons-5">Cons&lt;/h4>
&lt;ul>
&lt;li>Experiments and tests can sometimes break the application&lt;/li>
&lt;li>Scripting or automating AB tests can be complex&lt;/li>
&lt;/ul></description></item><item><title>22. System Design</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/22.-system-design/</link><pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/22.-system-design/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-introduction">A. Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-methodology---framework-for-system-design">B. Methodology - Framework for System Design&lt;/a>&lt;/li>
&lt;li>&lt;a href="#c-ml-model-development">C. ML Model Development&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#i-ml-operational-diffculties">I. ML Operational Diffculties&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#d-elements-of-distributed-systems">D. Elements of Distributed Systems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#i-microservices">I. Microservices&lt;/a>&lt;/li>
&lt;li>&lt;a href="#ii-service-discovery">II. Service Discovery&lt;/a>&lt;/li>
&lt;li>&lt;a href="#iii-load-balancing">III. Load Balancing&lt;/a>&lt;/li>
&lt;li>&lt;a href="#iv-databases">IV. Databases&lt;/a>&lt;/li>
&lt;li>&lt;a href="#v-caches">V. Caches&lt;/a>&lt;/li>
&lt;li>&lt;a href="#vi-file-system-storage">VI. File System Storage&lt;/a>&lt;/li>
&lt;li>&lt;a href="#vii-message-queues">VII. Message Queues&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-introduction">A. Introduction&lt;/h2>
&lt;p>The three stages to the interview:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Problem:&lt;/strong> The interviewer gives you a purposely vague task.&lt;/li>
&lt;li>&lt;strong>Clarification:&lt;/strong> You show leadership and experience by asking meaningful questions to clarify requirements and performance priorities.&lt;/li>
&lt;li>&lt;strong>Presentation:&lt;/strong> You give an impromptu presentation on solutions (probably as you’re thinking of the solution.)&lt;/li>
&lt;/ul>
&lt;h2 id="b-methodology---framework-for-system-design">B. Methodology - Framework for System Design&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>Always start with &lt;strong>clarification&lt;/strong>!&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Ask about the priorities, scale and restrictions of the system&lt;/p>
&lt;ul>
&lt;li>How many users?&lt;/li>
&lt;li>How much data?&lt;/li>
&lt;li>How many requests per second?&lt;/li>
&lt;li>Latency requirements?&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>After understanding the requirements, start with a &lt;strong>high level solution&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Start abstract and simple to lay out an end to end solution&lt;/li>
&lt;li>Draw an abstract diagram of the system&lt;/li>
&lt;li>the components should be technology agnostic and abstract away scaling and concrete methods&lt;/li>
&lt;li>eg: Checking whether the system prediction is real time, pre calculated batch or some hybrid&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Start filling in some details; &lt;strong>architectural components&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>eg: How models are delivered to the product? What type of infrastructure is required?&lt;/p>
&lt;ul>
&lt;li>Decribe the reasoning behind the design choices&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>add data models if necessary&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Start with &lt;strong>concerete component implementations&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Discuss the tradeoffs of the design choices&lt;/li>
&lt;li>eg: Why did you choose a particular database? Why did you choose a particular language?&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Finishing touches&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="c-ml-model-development">C. ML Model Development&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>Providing wide array of model types for the problem; it&amp;rsquo;s good to cover some breadth instead of naming one solution.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Offline training and evaluation&lt;/p>
&lt;ul>
&lt;li>Data used for training
&lt;ul>
&lt;li>How to deal with data imbalances?&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Metrics used to compare models- Precision, Recall, F1 Score, ROC AUC, etc.&lt;/li>
&lt;li>Evaluation methods
&lt;ul>
&lt;li>K-fold cross validation&lt;/li>
&lt;li>Training sample selection&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Online Evaluation&lt;/p>
&lt;ul>
&lt;li>Evaluate the model performance via A/B testing
&lt;ul>
&lt;li>What metrics to use?&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Model lifecycle management&lt;/p>
&lt;ul>
&lt;li>Monitoring the model to ensure its health&lt;/li>
&lt;li>Operations to track to keep model performance
&lt;ul>
&lt;li>How to manage the model lifecycle?&lt;/li>
&lt;li>How to deal with model drift?&lt;/li>
&lt;li>How to deal with model decay?&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="i-ml-operational-diffculties">I. ML Operational Diffculties&lt;/h3>
&lt;h4 id="a-ml-drifts">A. ML Drifts&lt;/h4>
&lt;figure id="figure-ml-drifts">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="ML Drifts" srcset="
/media/leetcode/Diagram-1-min-1024x424_hu88628b1d0352d1f015023a8a74ebc3da_15706_7240cdc27fda5c0d20c94668e94c3b39.webp 400w,
/media/leetcode/Diagram-1-min-1024x424_hu88628b1d0352d1f015023a8a74ebc3da_15706_7c75df37a5afdb5139b37afde66a76cc.webp 760w,
/media/leetcode/Diagram-1-min-1024x424_hu88628b1d0352d1f015023a8a74ebc3da_15706_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.siddeshsambasivam.com/media/leetcode/Diagram-1-min-1024x424_hu88628b1d0352d1f015023a8a74ebc3da_15706_7240cdc27fda5c0d20c94668e94c3b39.webp"
width="760"
height="315"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
ML Drifts
&lt;/figcaption>&lt;/figure>
&lt;ol>
&lt;li>Concept drift - The learned distribution changes over time due to behavioural changes&lt;/li>
&lt;li>Data drift - The learned distribution changes over time due to changes in the data&lt;/li>
&lt;/ol>
&lt;h4 id="what-to-do-about-it">What to do about it?&lt;/h4>
&lt;ol>
&lt;li>Setup data integrity and outlier monitoring
&lt;ul>
&lt;li>Data errors slowly degrade&lt;/li>
&lt;li>Missing values&lt;/li>
&lt;li>Broken data pipelines due to bugs or API updates&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Setup model drift monitoring&lt;/li>
&lt;/ol>
&lt;h2 id="d-elements-of-distributed-systems">D. Elements of Distributed Systems&lt;/h2>
&lt;p>Distributed system is &lt;em>an interconnected set of nodes that are linked by a network and share information between them.&lt;/em>&lt;/p>
&lt;h3 id="i-microservices">I. Microservices&lt;/h3>
&lt;p>A design paradigm where an application is structured to collect several independent services. The characteristics of these services include:&lt;/p>
&lt;ul>
&lt;li>Independent deployment&lt;/li>
&lt;li>Highly scalable&lt;/li>
&lt;li>Loosely coupled&lt;/li>
&lt;li>Highly maintainable and testable&lt;/li>
&lt;/ul>
&lt;h3 id="ii-service-discovery">II. Service Discovery&lt;/h3>
&lt;p>A service discovery is a mechanism that allows services to find and communicate with each other without hardcoding the location of each other.&lt;/p>
&lt;p>Eg: Apache zookeeper, consul, etcd&lt;/p>
&lt;h3 id="iii-load-balancing">III. Load Balancing&lt;/h3>
&lt;p>A device that acts as a &lt;strong>reverse proxy and distributes the network traffic&lt;/strong> across several different servers. There are two distinct types of load balancers:&lt;/p>
&lt;ol>
&lt;li>Layer 4
&lt;ul>
&lt;li>Act upon data found in network and transport layer protocols (IP, TCP, FTP, UDP)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Layer 7
&lt;ul>
&lt;li>Distributes requests based on application data (HTTP, HTTPS, FTP, SMTP)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Standard algorithms for load balancing:&lt;/p>
&lt;ul>
&lt;li>Round Robin&lt;/li>
&lt;li>Least Connections&lt;/li>
&lt;li>Least Response Time&lt;/li>
&lt;li>Weighted Round Robin&lt;/li>
&lt;/ul>
&lt;h3 id="iv-databases">IV. Databases&lt;/h3>
&lt;p>Refer to the databases page for more details.&lt;/p>
&lt;h3 id="v-caches">V. Caches&lt;/h3>
&lt;p>A temporary storage with smaller capacity in memory with fast access time.&lt;/p>
&lt;ol>
&lt;li>Client Caching&lt;/li>
&lt;li>CDN Caching&lt;/li>
&lt;li>Web Server Caching&lt;/li>
&lt;li>Database Caching&lt;/li>
&lt;li>Application Caching&lt;/li>
&lt;/ol>
&lt;h3 id="vi-file-system-storage">VI. File System Storage&lt;/h3>
&lt;p>A file is an unstructured collection of records. Two basic formats:&lt;/p>
&lt;ul>
&lt;li>Block storage - Organize data in blocks on disk&lt;/li>
&lt;li>Object storage
&lt;ul>
&lt;li>Amazon S3&lt;/li>
&lt;li>Highlty scalable&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="vii-message-queues">VII. Message Queues&lt;/h3>
&lt;p>Lets services to communicate with each other asynchronously. It is a &lt;strong>buffer&lt;/strong> between the producer and consumer.&lt;/p>
&lt;ol>
&lt;li>Producer - The service that produces the message and writes it to the queue&lt;/li>
&lt;li>Consumer - The service that consumes the message from the queue and reads it from the queue&lt;/li>
&lt;/ol>
&lt;p>Example: RabbitMQ, Kafka&lt;/p></description></item><item><title>23. Binary Search</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/23.-binary-search/</link><pubDate>Sun, 11 Sep 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/23.-binary-search/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-introduction">A. Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-leecode-problems">B. LeeCode Problems&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#704-binary-search">704. Binary Search&lt;/a>&lt;/li>
&lt;li>&lt;a href="#74-search-a-2d-matrix">74. Search a 2D Matrix&lt;/a>&lt;/li>
&lt;li>&lt;a href="#875-koko-eating-bananas">875. Koko Eating Bananas&lt;/a>&lt;/li>
&lt;li>&lt;a href="#4-median-of-two-sorted-arrays">4. Median of Two Sorted Arrays&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-introduction">A. Introduction&lt;/h2>
&lt;h2 id="b-leecode-problems">B. LeeCode Problems&lt;/h2>
&lt;h3 id="704-binary-search">704. Binary Search&lt;/h3>
&lt;p>Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return &lt;code>-1&lt;/code>.&lt;/p>
&lt;p>You must write an algorithm with &lt;code>O(log n)&lt;/code> runtime complexity.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums = [-1,0,3,5,9,12], target = 9 &lt;br>
&lt;strong>Output:&lt;/strong> 4 &lt;br>
&lt;strong>Explanation:&lt;/strong> 9 exists in nums and its index is 4&lt;/p>
&lt;/blockquote>
&lt;details class="spoiler " id="spoiler-1">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def search(self, nums: List[int], target: int) -&amp;gt; int:
&amp;quot;&amp;quot;&amp;quot;
0, 1, 2, 3, 4, 5
-1, 0, 3, 5, 9, 12
lr
0+5//2 = 2
0+1//2 = 0
&amp;quot;&amp;quot;&amp;quot;
if not nums:
return -1
l,r = 0, len(nums)-1
while l &amp;lt;= r:
mid = (l + r)//2
if nums[mid] == target:
return mid
elif nums[mid] &amp;lt; target:
l = mid + 1
else:
r = mid - 1
return -1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="74-search-a-2d-matrix">74. Search a 2D Matrix&lt;/h3>
&lt;p>Write an efficient algorithm that searches for a value &lt;code>target&lt;/code> in an &lt;code>m x n&lt;/code> integer matrix &lt;code>matrix&lt;/code>. This matrix has the following properties:&lt;/p>
&lt;ul>
&lt;li>Integers in each row are sorted from left to right&lt;/li>
&lt;li>The first integer of each row is greater than the last integer of the previous row&lt;/li>
&lt;/ul>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3 &lt;br>
&lt;strong>Output:&lt;/strong> true&lt;/p>
&lt;/blockquote>
&lt;details class="spoiler " id="spoiler-2">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;h4 id="key-ideas">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>The matrix can be treated as a sorted array&lt;/li>
&lt;li>Perform binary search on the rows to find the row where the target can be found
&lt;ul>
&lt;li>If the target is greater than the last element of the row, then the target can be found in the next row&lt;/li>
&lt;li>If the target is less than the first element of the row, then the target can be found in the previous row&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Implement 1D binary search on the row to find the target&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-python">
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -&amp;gt; bool:
t,b = 0, len(matrix)-1
while t &amp;lt;= b :
row = (t+b)//2
if matrix[row][-1] &amp;lt; target:
t = row + 1
elif matrix[row][0] &amp;gt; target:
b = row - 1
else:
break
if t &amp;gt; b:
return False
# binary search on the row
l,r = 0, len(matrix[0])-1
while l &amp;lt;= r:
mid = (l+r)//2
if matrix[row][mid] == target:
return True
elif matrix[row][mid] &amp;lt; target:
l = mid + 1
else:
r = mid -1
return False
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="875-koko-eating-bananas">875. Koko Eating Bananas&lt;/h3>
&lt;p>Koko loves to eat bananas. There are &lt;code>n&lt;/code> piles of bananas, the &lt;code>ith&lt;/code> pile has &lt;code>piles[i]&lt;/code> bananas. The guards have gone and will come back in &lt;code>h&lt;/code> hours.&lt;/p>
&lt;p>Koko can decide her bananas-per-hour eating speed of &lt;code>k&lt;/code>. Each hour, she chooses some pile of bananas and eats &lt;code>k&lt;/code> bananas from that pile. If the pile has less than &lt;code>k&lt;/code> bananas, she eats all of them instead and will not eat any more bananas during this hour.&lt;/p>
&lt;p>Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.&lt;/p>
&lt;p>Return the minimum integer &lt;code>k&lt;/code> such that she can eat all the bananas within &lt;code>h&lt;/code> hours.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> piles = [3,6,7,11], h = 8 &lt;br>
&lt;strong>Output:&lt;/strong> 4&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>The &lt;code>k&lt;/code> can be found iteratively using binary search
&lt;ul>
&lt;li>Search for a &lt;code>k&lt;/code> that satisfies the condition that the number of hours required to eat all the bananas is less than or equal to &lt;code>h&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>@BaseCase&lt;/code> The maximum value of &lt;code>k&lt;/code> is the maximum value of the &lt;code>piles&lt;/code>&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-3">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
import math
class Solution:
def minEatingSpeed(self, piles: List[int], h: int) -&amp;gt; int:
maxPiles = max(piles)
l,r = 1, maxPiles
res = maxPiles
while l &amp;lt;= r:
hrs = 0
k = (l+r)//2
for pile in piles:
hrs += math.ceil(pile/k)
if hrs &amp;lt;= h:
res = min(res, k)
r = k-1
else:
l = k+1
return res
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details>
&lt;h3 id="4-median-of-two-sorted-arrays">4. Median of Two Sorted Arrays&lt;/h3>
&lt;p>Given two sorted arrays &lt;code>nums1&lt;/code> and &lt;code>nums2&lt;/code> of size &lt;code>m&lt;/code> and &lt;code>n&lt;/code> respectively, return &lt;strong>the median&lt;/strong> of the two sorted arrays.&lt;/p>
&lt;p>The overall run time complexity should be &lt;code>O(log (m+n))&lt;/code>.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Input:&lt;/strong> nums1 = [1,3], nums2 = [2] &lt;br>
&lt;strong>Output:&lt;/strong> 2.00000 &lt;br>
&lt;strong>Explanation:&lt;/strong> merged array = [1,2,3] and median is 2.&lt;/p>
&lt;/blockquote>
&lt;h4 id="key-ideas-1">Key Ideas&lt;/h4>
&lt;ul>
&lt;li>&lt;code>@KeyAlgorithm&lt;/code> Binary Search on the smaller array to find the partition point
&lt;ul>
&lt;li>Move the partition point based on the following condition
$$B_{min}\le A_{max} \ \text{and} \ B_{max} \ge A_{min}$$
&lt;ul>
&lt;li>If the above condition is satisfied, then the array is partitioned right
&lt;ul>
&lt;li>Even, median = $(max(A_{min}, B_{min})+min(A_{max}, B_{max}))/2$&lt;/li>
&lt;li>Odd, median = $min(A_{max}, B_{max})$&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>If $B_{min}$ is greater than $A_{max}$, then &lt;code>l&lt;/code> is moved to &lt;code>mid+1&lt;/code>&lt;/li>
&lt;li>If $B_{max}$ is less than $A_{min}$, then &lt;code>r&lt;/code> is moved to &lt;code>mid-1&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;details class="spoiler " id="spoiler-4">
&lt;summary>Code&lt;/summary>
&lt;p>&lt;pre>&lt;code class="language-python">
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -&amp;gt; float:
if len(nums1) &amp;gt; len(nums2):
nums2, nums1 = nums1, nums2
m,n = len(nums1), len(nums2)
total_len = m+n
half = total_len//2
l,r = 0, m-1
while True:
a_mid = (l+r)//2
Amin = nums1[a_mid] if a_mid &amp;gt;= 0 else float(&amp;quot;-inf&amp;quot;)
Amax = nums1[a_mid+1] if a_mid+1 &amp;lt; m else float(&amp;quot;inf&amp;quot;)
b_mid = half-a_mid-2 # both a_mid and half needs to be zero indexed
Bmin = nums2[b_mid] if b_mid &amp;gt;= 0 else float(&amp;quot;-inf&amp;quot;)
Bmax = nums2[b_mid+1] if b_mid+1 &amp;lt; n else float(&amp;quot;inf&amp;quot;)
if Bmin &amp;lt;= Amax and Bmax &amp;gt;= Amin:
if total_len % 2 == 0:
return (max(Amin, Bmin)+min(Amax, Bmax))/2
return min(Amax, Bmax)
elif Bmin &amp;gt; Amax:
l = a_mid + 1
else:
r = a_mid - 1
&lt;/code>&lt;/pre>
&lt;/p>
&lt;/details></description></item><item><title>24. Sorting</title><link>https://www.siddeshsambasivam.com/notes/cs-concepts/24.-sorting/</link><pubDate>Sun, 11 Sep 2022 00:00:00 +0000</pubDate><guid>https://www.siddeshsambasivam.com/notes/cs-concepts/24.-sorting/</guid><description>&lt;details class="toc-inpage d-print-none " open>
&lt;summary class="font-weight-bold">Table of Contents&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#a-bubble-sort">A. Bubble sort&lt;/a>&lt;/li>
&lt;li>&lt;a href="#b-selection-sort">B. Selection sort&lt;/a>&lt;/li>
&lt;li>&lt;a href="#c-merge-sort">C. Merge sort&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;h2 id="a-bubble-sort">A. Bubble sort&lt;/h2>
&lt;p>Bubble sort is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements and swaps them if they are in the wrong order.&lt;/p>
&lt;pre>&lt;code class="language-python">
def bubble_sort(arr:List[int]) -&amp;gt; List[int]:
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] &amp;gt; arr[j]:
arr[i], arr[j] = arr[j], arr[i]
return arr
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Time complexity&lt;/strong> &lt;code>O(n^2)&lt;/code> &lt;br>
&lt;strong>Space complexity&lt;/strong> &lt;code>O(1)&lt;/code>&lt;/p>
&lt;h2 id="b-selection-sort">B. Selection sort&lt;/h2>
&lt;p>The selection sort algorithm sorts an array by repeatedly finding the minimum element (considering ascending order) from unsorted part and putting it at the beginning. The algorithm maintains two subarrays in a given array.&lt;/p>
&lt;pre>&lt;code class="language-python">
def selection_sort(arr:List[int]) -&amp;gt; List[int]:
for i in range(len(arr)):
min_idx = i
for j in range(i+1, len(arr)):
if arr[min_idx] &amp;gt; arr[j]:
min_idx = j
arr[min_idx], arr[i] = arr[i], arr[min_idx]
return arr
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Time complexity&lt;/strong> &lt;code>O(n^2)&lt;/code> &lt;br>
&lt;strong>Space complexity&lt;/strong> &lt;code>O(1)&lt;/code>&lt;/p>
&lt;div class="alert alert-note">
&lt;div>
Selection sort performs a smaller number of swaps compared to bubble sort
&lt;/div>
&lt;/div>
&lt;h2 id="c-merge-sort">C. Merge sort&lt;/h2>
&lt;p>Merge sort is a divide and conquer algorithm that was invented by John von Neumann in 1945. It divides the input array into two halves, calls itself for the two halves, and then merges the two sorted halves.&lt;/p>
&lt;pre>&lt;code class="language-python">
def merge(a:List[int], b:List[int]) -&amp;gt; List[int]:
p,q = 0,0
res = []
while p &amp;lt; len(a) and q &amp;lt; len(b):
if a[p] &amp;lt; b[q]:
res.append(a[p])
p += 1
else:
res.append(b[q])
q += 1
while p &amp;lt; len(a):
res.append(a[p])
p += 1
while q &amp;lt; len(b):
res.append(b[q])
q += 1
return res
def merge_sort(arr:List[int]) -&amp;gt; List[int]:
if len(arr) &amp;lt; 2:
return arr
mid = len(arr)//2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid+1:])
return merge(left, right)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Time complexity&lt;/strong> &lt;code>O(nlogn)&lt;/code> &lt;br>
&lt;strong>Space complexity&lt;/strong> &lt;code>O(n)&lt;/code>&lt;/p></description></item></channel></rss>