<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[Albert Kovalevskij]]></title>
        <description><![CDATA[Albert Kovalevskij's blog]]></description>
        <link>https://albert-kovalevskij.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Sun, 24 Mar 2024 10:01:09 GMT</lastBuildDate>
        <atom:link href="https://albert-kovalevskij.com/feed.xml" rel="self" type="application/rss+xml"/>
        <language><![CDATA[en]]></language>
        <item>
            <title><![CDATA[Solving Binary Tree Maximum Path Sum: Finding the Highest Valued Path]]></title>
            <description><![CDATA[<p>The &quot;Binary Tree Maximum Path Sum&quot; problem involves finding a path in a binary tree that produces the highest sum of values. The path may start and end at any node in the tree and can traverse up or down through the tree.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a non-empty binary tree, find the maximum path sum. The path must contain at least one node and does not need to go through the root.</p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:<br><img src="/assets/blind-75/124.binary-tree-maximum-path-sum/exx1.jpg" alt="Binary Tree"></p>
<p><strong>Input:</strong> </p>
<pre><code class="language-typescript">root = [1,2,3]
</code></pre>
<p><strong>Output:</strong> </p>
<pre><code class="language-typescript">6
</code></pre>
<p><strong>Explanation:</strong> The optimal path is 2 -&gt; 1 -&gt; 3 with a path sum of 2 + 1 + 3 = 6.</p>
<p><img src="/assets/blind-75/124.binary-tree-maximum-path-sum/exx2.jpg" alt="Binary Tree"><br><strong>Input:</strong> </p>
<pre><code class="language-typescript">root = [-10,9,20,null,null,15,7]
</code></pre>
<p><strong>Output:</strong> </p>
<pre><code class="language-typescript">42
</code></pre>
<p><strong>Explanation:</strong> The optimal path is 15 -&gt; 20 -&gt; 7 with a path sum of 15 + 20 + 7 = 42.</p>
<h2 id="solution-approach---recursive-depth-first-search">Solution Approach - Recursive Depth-First Search</h2>
<pre><code class="language-typescript">class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = (val === undefined ? 0 : val);
    this.left = (left === undefined ? null : left);
    this.right = (right === undefined ? null : right);
  }
}

function maxPathSum(root: TreeNode | null): number {
  let maxSum = Number.MIN_SAFE_INTEGER;

  function maxGain(node: TreeNode | null): number {
    if (node === null) return 0;

    const leftGain = Math.max(maxGain(node.left), 0);
    const rightGain = Math.max(maxGain(node.right), 0);

    const priceNewPath = node.val + leftGain + rightGain;
    maxSum = Math.max(maxSum, priceNewPath);

    return node.val + Math.max(leftGain, rightGain);
  }

  maxGain(root);
  return maxSum;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Function</strong>: The <code>maxGain</code> function calculates the maximum sum starting from each node.</p>
</li>
<li><p><strong>Path Sum Calculation</strong>: At each node, calculate the maximum sum of any path that includes the node.</p>
</li>
<li><p><strong>Global Maximum</strong>: Track the maximum path sum found in the entire tree.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Binary Tree Maximum Path Sum problem is a complex and intriguing challenge, showcasing the depth and flexibility of recursive algorithms in tree data structures.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-binary-tree-maximum-path-sum</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-binary-tree-maximum-path-sum</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 27 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Merge k Sorted Lists: Combining Multiple Sorted Lists]]></title>
            <description><![CDATA[<p>The &quot;Merge k Sorted Lists&quot; problem is about combining multiple sorted linked lists into one single sorted list.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of <code>k</code> linked-lists <code>lists</code>, each linked-list is sorted in ascending order. Merge all the linked-lists into one sorted linked list and return it.</p>
<h2 id="example">Example</h2>
<p>Consider <code>k</code> sorted linked lists:</p>
<h3 id="example-1">Example 1</h3>
<ul>
<li><strong>Input</strong>: lists = <code>[[1,4,5],[1,3,4],[2,6]]</code></li>
<li><strong>Output</strong>: <code>[1,1,2,3,4,4,5,6]</code></li>
<li><strong>Explanation</strong>: The linked-lists are:</li>
</ul>
<pre><code class="language-json">[
1 -&gt; 4 -&gt; 5,
1 -&gt; 3 -&gt; 4,
2 -&gt; 6
]
</code></pre>
<p>Merging them into one sorted list results in <code>1 -&gt; 1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 4 -&gt; 5 -&gt; 6</code>.</p>
<h3 id="example-2">Example 2</h3>
<ul>
<li><strong>Input</strong>: lists = <code>[]</code></li>
<li><strong>Output</strong>: <code>[]</code></li>
<li><strong>Explanation</strong>: No lists to merge, so the output is an empty list.</li>
</ul>
<h3 id="example-3">Example 3</h3>
<ul>
<li><strong>Input</strong>: lists = <code>[[]]</code></li>
<li><strong>Output</strong>: <code>[]</code></li>
<li><strong>Explanation</strong>: A single empty list results in an empty merged list.</li>
</ul>
<h2 id="solution-approach">Solution Approach</h2>
<p>A popular approach to solving this problem is using a Min Heap or a Priority Queue to efficiently find and merge the smallest elements of the lists. </p>
<h2 id="solution-approach---min-heap">Solution Approach - Min Heap</h2>
<pre><code class="language-typescript">class ListNode {
  val: number;
  next: ListNode | null;
  constructor(val?: number, next?: ListNode | null) {
    this.val = val === undefined ? 0 : val;
    this.next = next === undefined ? null : next;
  }
}

class MinHeap {
  private heap: Array&lt;ListNode | null&gt;;

  constructor() {
    this.heap = [];
  }

  private getLeftChildIndex(parentIndex: number): number {
    return 2 * parentIndex + 1;
  }

  private getRightChildIndex(parentIndex: number): number {
    return 2 * parentIndex + 2;
  }

  private getParentIndex(childIndex: number): number {
    return Math.floor((childIndex - 1) / 2);
  }

  private hasLeftChild(index: number): boolean {
    return this.getLeftChildIndex(index) &lt; this.heap.length;
  }

  private hasRightChild(index: number): boolean {
    return this.getRightChildIndex(index) &lt; this.heap.length;
  }

  private hasParent(index: number): boolean {
    return this.getParentIndex(index) &gt;= 0;
  }

  private leftChild(index: number): ListNode | null {
    return this.heap[this.getLeftChildIndex(index)];
  }

  private rightChild(index: number): ListNode | null {
    return this.heap[this.getRightChildIndex(index)];
  }

  private parent(index: number): ListNode | null {
    return this.heap[this.getParentIndex(index)];
  }

  private swap(indexOne: number, indexTwo: number): void {
    const temp = this.heap[indexOne];
    this.heap[indexOne] = this.heap[indexTwo];
    this.heap[indexTwo] = temp;
  }

  public isEmpty(): boolean {
    return this.heap.length === 0;
  }

  public insert(node: ListNode | null): void {
    this.heap.push(node);
    this.heapifyUp();
  }

  public extract(): ListNode | null {
    if (this.isEmpty()) {
      return null;
    }
    const node = this.heap[0];
    this.heap[0] = this.heap[this.heap.length - 1];
    this.heap.pop();
    this.heapifyDown();
    return node;
  }

  private heapifyUp(): void {
    let index = this.heap.length - 1;
    while (this.hasParent(index) &amp;&amp; this.parent(index)!.val &gt; this.heap[index]!.val) {
      this.swap(this.getParentIndex(index), index);
      index = this.getParentIndex(index);
    }
  }

  private heapifyDown(): void {
    let index = 0;
    while (this.hasLeftChild(index)) {
      let smallerChildIndex = this.getLeftChildIndex(index);
      if (this.hasRightChild(index) &amp;&amp; this.rightChild(index)!.val &lt; this.leftChild(index)!.val) {
        smallerChildIndex = this.getRightChildIndex(index);
      }

      if (this.heap[index]!.val &lt; this.heap[smallerChildIndex]!.val) {
        break;
      } else {
        this.swap(index, smallerChildIndex);
      }
      index = smallerChildIndex;
    }
  }
}

function mergeKLists(lists: Array&lt;ListNode | null&gt;): ListNode | null {
  const minHeap = new MinHeap();
  lists.forEach(list =&gt; {
    if (list) minHeap.insert(list);
  });

  const dummy = new ListNode(0);
  let current = dummy;

  while (!minHeap.isEmpty()) {
    let node = minHeap.extract();
    current.next = node;
    if (current.next) {
      current = current.next;
    }
    if (node &amp;&amp; node.next) {
      minHeap.insert(node.next);
    }
  }

  return dummy.next;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<p>The provided TypeScript solution for merging <code>k</code> sorted linked lists implements a custom Min Heap class and uses it to efficiently merge the lists. Here&#39;s a breakdown of how the solution works:</p>
<h3 id="listnode-class"><code>ListNode</code> Class</h3>
<ul>
<li>Represents a node in a linked list.</li>
<li>Contains a value (<code>val</code>) and a reference to the next node (<code>next</code>).</li>
</ul>
<h3 id="minheap-class"><code>MinHeap</code> Class</h3>
<ul>
<li>A min heap is a binary tree where the parent node is always less than or equal to its children.</li>
<li>The class maintains a heap in an array (<code>heap</code>), where each element is a <code>ListNode</code> or <code>null</code>.</li>
</ul>
<h4 id="key-methods-and-properties">Key Methods and Properties:</h4>
<ul>
<li><code>getLeftChildIndex</code>, <code>getRightChildIndex</code>, <code>getParentIndex</code>: Calculate the indices of a node&#39;s left child, right child, and parent.</li>
<li><code>hasLeftChild</code>, <code>hasRightChild</code>, <code>hasParent</code>: Check if the node at the given index has a left child, right child, or parent.</li>
<li><code>leftChild</code>, <code>rightChild</code>, <code>parent</code>: Get the left child, right child, or parent of the node at the given index.</li>
<li><code>swap</code>: Swap two nodes in the heap.</li>
<li><code>isEmpty</code>: Check if the heap is empty.</li>
<li><code>insert</code>: Add a new node to the heap and reorganize the heap to maintain the min heap property (heapify up).</li>
<li><code>extract</code>: Remove and return the smallest node from the heap and reorganize the heap (heapify down).</li>
</ul>
<h3 id="mergeklists-function"><code>mergeKLists</code> Function</h3>
<ul>
<li>Merges <code>k</code> sorted linked lists into one sorted linked list.</li>
<li>Uses the Min Heap to efficiently find the smallest current node among all the lists.</li>
<li>Iteratively extracts the smallest node from the heap and adds it to the merged list.</li>
<li>If the extracted node has a next node, inserts the next node into the heap.</li>
</ul>
<h4 id="process">Process:</h4>
<ol>
<li><strong>Initialize Min Heap</strong>: All head nodes of the <code>k</code> lists are inserted into the min heap.</li>
<li><strong>Merging</strong>: Continuously extract the smallest node from the heap and attach it to the merged list.</li>
<li><strong>Insert Next Nodes</strong>: If the extracted node has a next node, insert that next node into the heap to be considered in subsequent extractions.</li>
<li><strong>Completion</strong>: The process continues until the heap is empty, meaning all nodes have been merged into the new list.</li>
</ol>
<p>The result is a new linked list, pointed to by <code>dummy.next</code>, which is a sorted merge of all the input linked lists. This approach efficiently handles the merging process, making it suitable for a large number of lists or lists with a large number of nodes.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Merging k sorted lists is a classic problem that demonstrates the practical application of heap data structures in sorting and merging operations.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-merge-k-sorted-lists</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-merge-k-sorted-lists</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 27 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Find Median from Data Stream: Continuous Median Calculation]]></title>
            <description><![CDATA[<p>The &quot;Find Median from Data Stream&quot; problem involves creating a data structure that can continuously provide the median of a dynamically changing set of numbers. This challenge tests the ability to efficiently insert numbers and calculate the median at any point.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Design a data structure that supports the following two operations:</p>
<ul>
<li><code>void addNum(int num)</code>: Add a number to the data structure.</li>
<li><code>double findMedian()</code>: Return the median of all elements so far.</li>
</ul>
<h2 id="example">Example</h2>
<ul>
<li><strong>Operations</strong>: <code>addNum(1)</code>, <code>addNum(2)</code>, <code>findMedian()</code>, <code>addNum(3)</code>, <code>findMedian()</code></li>
<li><strong>Outputs</strong>: [null, null, 1.5, null, 2.0]</li>
</ul>
<h2 id="solution-approach---two-heaps">Solution Approach - Two Heaps</h2>
<p>The solution utilizes two heaps (a max heap and a min heap) to maintain the elements in sorted order and allow for efficient median calculation.</p>
<pre><code class="language-typescript">MedianFinder {
  private maxHeap: Heap&lt;number&gt;;
  private minHeap: Heap&lt;number&gt;;

  constructor() {
    this.maxHeap = new Heap&lt;number&gt;((a, b) =&gt; b - a);
    this.minHeap = new Heap&lt;number&gt;((a, b) =&gt; a - b);
  }

  addNum(num: number): void {
    // Add to maxHeap if it&#39;s empty or the number is less than or equal to its top element
    if (this.maxHeap.isEmpty() || num &lt;= this.maxHeap.peek()!) {
      this.maxHeap.insert(num);
    } else {
      this.minHeap.insert(num);
    }

    // Balancing the heaps: ensure maxHeap has the same or one more element than minHeap
    if (this.maxHeap.size() &gt; this.minHeap.size() + 1) {
      this.minHeap.insert(this.maxHeap.extract()!);
    } else if (this.minHeap.size() &gt; this.maxHeap.size()) {
      this.maxHeap.insert(this.minHeap.extract()!);
    }
  }

  findMedian(): number {
    if (this.maxHeap.size() === this.minHeap.size()) {
      // If both heaps have the same size, the median is the average of their tops
      return (this.maxHeap.peek()! + this.minHeap.peek()!) / 2;
    } else {
      // If maxHeap has more elements, the median is its top element
      return this.maxHeap.peek()!;
    }
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<p>The <code>MedianFinder</code> class is an elegant solution to the &quot;Find Median from Data Stream&quot; problem, utilizing two heaps—a max heap and a min heap. Here&#39;s a breakdown of how this solution works:</p>
<h3 id="class-medianfinder">Class: <code>MedianFinder</code></h3>
<ul>
<li>Manages two heaps to store the lower and upper halves of the data stream.</li>
</ul>
<h4 id="properties">Properties:</h4>
<ul>
<li><code>maxHeap</code>: A max heap (<code>Heap&lt;number&gt;</code>) to store the smaller half of the numbers. The top of this heap will always be the largest number of the lower half.</li>
<li><code>minHeap</code>: A min heap (<code>Heap&lt;number&gt;</code>) to store the larger half of the numbers. The top of this heap will always be the smallest number of the upper half.</li>
</ul>
<h4 id="constructor">Constructor:</h4>
<ul>
<li>Initializes the two heaps. The max heap uses a comparator that favors larger values (<code>b - a</code>), and the min heap uses a comparator that favors smaller values (<code>a - b</code>).</li>
</ul>
<h4 id="method-addnumnum-number">Method: <code>addNum(num: number)</code></h4>
<ul>
<li>Inserts a new number into one of the two heaps.</li>
<li>If the number is less than or equal to the top of the max heap, or if the max heap is empty, it&#39;s added to the max heap. Otherwise, it&#39;s added to the min heap.</li>
<li>After insertion, the method checks and rebalances the heaps to ensure that their sizes differ by no more than one element. This rebalancing is crucial for the median calculation.</li>
</ul>
<h4 id="method-findmedian-number">Method: <code>findMedian(): number</code></h4>
<ul>
<li>Returns the median of the current set of numbers.</li>
<li>If the heaps are of equal size, the median is the average of the tops of the two heaps.</li>
<li>If the heaps are of unequal size, the median is the top of the larger heap (which, in this implementation, is always the max heap).</li>
</ul>
<h3 id="how-it-works">How It Works:</h3>
<ul>
<li>The max heap and min heap effectively split the data stream into two halves.</li>
<li>By maintaining the size property (the max heap is always equal or one more than the min heap), the class can quickly calculate the median.</li>
<li>When a new number is added, it&#39;s placed in the correct half of the data. If this insertion unbalances the heaps, the class moves the top element of the larger heap to the smaller heap.</li>
<li>For finding the median, if the sizes are equal, the median is the average of the two middle numbers. If not, it&#39;s just the middle number (from the max heap).</li>
</ul>
<p>This implementation is efficient and dynamic, making it well-suited for a situation where data is continuously streaming, and the median needs to be recalculated frequently.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Find Median from Data Stream problem showcases the utility of heap data structures in maintaining a running median in an efficient and scalable way.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-find-median-from-data-stream</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-find-median-from-data-stream</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 27 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Top K Frequent Elements: Identifying Most Common Items]]></title>
            <description><![CDATA[<p>The &quot;Top K Frequent Elements&quot; problem involves identifying the most commonly occurring elements in an array. This challenge is about efficiently finding the elements that appear most frequently.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a non-empty array of integers, return the k most frequent elements.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>:</li>
</ul>
<pre><code class="language-typescript">nums = [1,1,1,2,2,3], k = 2
</code></pre>
<ul>
<li><strong>Output</strong>:</li>
</ul>
<pre><code class="language-typescript">[1,2]
</code></pre>
<ul>
<li><strong>Explanation</strong>: The two most frequent elements are 1 and 2, which both appear three and two times respectively.</li>
</ul>
<h2 id="solution-approach---heap-and-hash-map">Solution Approach - Heap and Hash Map</h2>
<p>The solution involves using a hash map to count the frequency of each element and then using a heap to efficiently extract the k most frequent elements.</p>
<pre><code class="language-typescript">function topKFrequent(nums: number[], k: number): number[] {
    const frequencyMap: { [key: number]: number } = {};
    for (const num of nums) {
        frequencyMap[num] = (frequencyMap[num] || 0) + 1;
    }

    const minHeap = new MinHeap&lt;number&gt;((a, b) =&gt; frequencyMap[a] - frequencyMap[b]);
    Object.keys(frequencyMap).forEach(num =&gt; {
        minHeap.insert(parseInt(num));
        if (minHeap.size() &gt; k) {
            minHeap.extract();
        }
    });

    return minHeap.getItems();
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><strong>Frequency Count</strong>: Use a hash map to count the occurrences of each number.</li>
<li><strong>Min Heap</strong>: A min heap is used to keep track of the top k frequent elements.</li>
<li><strong>Heap Operations</strong>: Insert each number into the heap. If the heap size exceeds k, remove the smallest element (based on frequency).</li>
<li><strong>Result</strong>: The contents of the heap represent the top k frequent elements.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Top K Frequent Elements problem is a great example of combining data structures - hash maps for frequency counting and heaps for efficient element retrieval - to solve a common algorithmic challenge.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-top-k-frequent-elements</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-top-k-frequent-elements</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 27 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Word Search II: Finding Words on a Board]]></title>
            <description><![CDATA[<p>The &quot;Word Search II&quot; problem involves searching for all possible words from a given list within a grid of letters. This task requires efficiently traversing the grid and checking for the presence of words.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an <code>m x n</code> board of characters and a list of strings <code>words</code>, return all words on the board. Each word must be constructed from letters of sequentially adjacent cells, where &quot;adjacent&quot; cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.</p>
<h2 id="example">Example</h2>
<p>Consider a board and a list of words:</p>
<p><img src="/assets/blind-75/212.word-search-II/search1.jpg" alt="Example 1"><br><strong>Input:</strong> </p>
<pre><code class="language-javascript">board = [[&quot;o&quot;,&quot;a&quot;,&quot;a&quot;,&quot;n&quot;],[&quot;e&quot;,&quot;t&quot;,&quot;a&quot;,&quot;e&quot;],[&quot;i&quot;,&quot;h&quot;,&quot;k&quot;,&quot;r&quot;],[&quot;i&quot;,&quot;f&quot;,&quot;l&quot;,&quot;v&quot;]]
words = [&quot;oath&quot;,&quot;pea&quot;,&quot;eat&quot;,&quot;rain&quot;]
</code></pre>
<p><strong>Output:</strong> </p>
<pre><code class="language-json">[&quot;eat&quot;,&quot;oath&quot;]
</code></pre>
<p><img src="/assets/blind-75/212.word-search-II/search2.jpg" alt="Example 2"><br><strong>Input:</strong> </p>
<pre><code class="language-javascript">board = [[&quot;a&quot;,&quot;b&quot;],[&quot;c&quot;,&quot;d&quot;]], words = [&quot;abcb&quot;]
</code></pre>
<p><strong>Output:</strong> </p>
<pre><code class="language-json">[]
</code></pre>
<h2 id="solution-approach---trie-and-backtracking">Solution Approach - Trie and Backtracking</h2>
<pre><code class="language-typescript">class TrieNode {
  children: Map&lt;string, TrieNode&gt;;
  word: string | null;

  constructor() {
    this.children = new Map();
    this.word = null;
  }
}

class Trie {
  root: TrieNode;

  constructor() {
    this.root = new TrieNode();
  }

  insert(word: string): void {
    let node = this.root;
    for (const char of word) {
      if (!node.children.has(char)) {
        node.children.set(char, new TrieNode());
      }
      node = node.children.get(char)!;
    }
    node.word = word; // Store word at the leaf
  }
}

function findWords(board: string[][], words: string[]): string[] {
  const trie = new Trie();
  for (const word of words) {
    trie.insert(word);
  }

  const foundWords: string[] = [];
  for (let i = 0; i &lt; board.length; i++) {
    for (let j = 0; j &lt; board[i].length; j++) {
      dfs(board, i, j, trie.root, foundWords);
    }
  }

  function dfs(board: string[][], i: number, j: number, node: TrieNode, result: string[]) {
    const char = board[i][j];
    if (!node.children.has(char)) return;

    const nextNode = node.children.get(char);
    if (nextNode!.word) {
      // Found a word
      result.push(nextNode!.word);
      nextNode!.word = null; // Avoid duplicate entries
    }

    board[i][j] = &#39;#&#39;; // Mark as visited
    const directions = [
      [0, 1],
      [1, 0],
      [0, -1],
      [-1, 0],
    ]; // Right, Down, Left, Up
    for (const [dx, dy] of directions) {
      const x = i + dx,
        y = j + dy;
      if (x &gt;= 0 &amp;&amp; x &lt; board.length &amp;&amp; y &gt;= 0 &amp;&amp; y &lt; board[0].length) {
        dfs(board, x, y, nextNode!, result);
      }
    }
    board[i][j] = char; // Reset
  }

  return foundWords;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Trie for Word Storage</strong>: Store the list of words in a Trie for efficient searching.</p>
</li>
<li><p><strong>Backtracking for Grid Traversal</strong>: Use depth-first search (DFS) with backtracking to explore the board.</p>
</li>
<li><p><strong>Finding Words</strong>: On each step of DFS, check if the current path corresponds to a word in the Trie.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Word Search II is a challenging problem that combines Trie data structures with backtracking techniques, demonstrating advanced concepts in algorithm design and optimization.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-word-search-ii</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-word-search-ii</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Thu, 25 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Implement Trie (Prefix Tree): Building a Searchable Data Structure]]></title>
            <description><![CDATA[<p>The &quot;Implement Trie (Prefix Tree)&quot; problem involves building a Trie, a special type of tree used to efficiently store a dynamic set of strings. Tries are used for searching, inserting, and performing prefix operations in a collection of strings.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Design a Trie data structure that supports insertion, search, and prefix search operations efficiently.</p>
<h2 id="example-of-trie-functionality">Example of Trie Functionality</h2>
<ul>
<li><strong>Insert</strong>: Adding words like &quot;apple&quot; and &quot;app&quot; into the Trie.</li>
<li><strong>Search</strong>: Checking if a word like &quot;apple&quot; is in the Trie.</li>
<li><strong>Starts With</strong>: Checking if there are any words that start with a prefix like &quot;app&quot;.</li>
</ul>
<h2 id="solution-approach---trie-implementation">Solution Approach - Trie Implementation</h2>
<pre><code class="language-typescript">export class TrieNode {
  children: Map&lt;string, TrieNode&gt;;
  isEndOfWord: boolean;

  constructor() {
    this.children = new Map();
    this.isEndOfWord = false;
  }
}

export class Trie {
  root: TrieNode;

  constructor() {
    this.root = new TrieNode();
  }

  insert(word: string): void {
    let node = this.root;
    for (const char of word) {
      if (!node.children.has(char)) {
        node.children.set(char, new TrieNode());
      }
      node = node.children.get(char)!;
    }
    node.isEndOfWord = true;
  }

  search(word: string): boolean {
    let node = this.root;
    for (const char of word) {
      if (!node.children.has(char)) {
        return false;
      }
      node = node.children.get(char)!;
    }
    return node.isEndOfWord;
  }

  startsWith(prefix: string): boolean {
    let node = this.root;
    for (const char of prefix) {
      if (!node.children.has(char)) {
        return false;
      }
      node = node.children.get(char)!;
    }
    return true;
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>TrieNode Class</strong>: Represents each node in the Trie, holding children and a flag to indicate end of a word.</p>
</li>
<li><p><strong>Trie Class</strong>: Implements the Trie with methods for <code>insert</code>, <code>search</code>, and <code>startsWith</code>.</p>
</li>
<li><p><strong>Efficient Operations</strong>: Leveraging the Trie structure for quick lookups and prefix searches.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Implementing a Trie is a crucial exercise in understanding tree-like data structures and their application in efficiently managing and searching strings.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-implement-trie-prefix-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-implement-trie-prefix-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Design Add and Search Words Data Structure: Implementing an Advanced Trie]]></title>
            <description><![CDATA[<p>The &quot;Design Add and Search Words Data Structure&quot; problem involves developing a data structure that not only stores a collection of strings but also supports searching with wildcard characters.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Design a data structure that supports adding new words and finding if a string matches any previously added string. The search method should be able to handle wildcard characters, where a <code>.</code> character can represent any letter.</p>
<h2 id="example-of-functionality">Example of Functionality</h2>
<ul>
<li><strong>Add Word</strong>: Add words like &quot;bad&quot;, &quot;dad&quot;, and &quot;mad&quot; to the data structure.</li>
<li><strong>Search</strong>: Perform searches like &quot;.ad&quot; (matches &quot;bad&quot;, &quot;dad&quot;, &quot;mad&quot;), &quot;b..&quot; (matches &quot;bad&quot;).</li>
</ul>
<h2 id="solution-approach---trie-with-backtracking">Solution Approach - Trie with Backtracking</h2>
<pre><code class="language-typescript">class TrieNode {
  children: Map&lt;string, TrieNode&gt;;
  isEndOfWord: boolean;

  constructor() {
    this.children = new Map();
    this.isEndOfWord = false;
  }
}

class WordDictionary {
  root: TrieNode;

  constructor() {
    this.root = new TrieNode();
  }

  addWord(word: string): void {
    let node = this.root;
    for (const char of word) {
      if (!node.children.has(char)) {
        node.children.set(char, new TrieNode());
      }
      node = node.children.get(char)!;
    }
    node.isEndOfWord = true;
  }

  search(word: string): boolean {
    return this.searchInNode(word, this.root);
  }

  private searchInNode(word: string, node: TrieNode): boolean {
    for (let i = 0; i &lt; word.length; i++) {
      const char = word.charAt(i);
      if (!node.children.has(char)) {
        if (char === &#39;.&#39;) {
          for (const [_, childNode] of node.children) {
            if (this.searchInNode(word.substring(i + 1), childNode)) {
              return true;
            }
          }
        }
        return false;
      } else {
        node = node.children.get(char)!;
      }
    }
    return node.isEndOfWord;
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Trie Structure</strong>: The core of this data structure is a Trie to store the words efficiently.</p>
</li>
<li><p><strong>Wildcard Handling</strong>: The search method incorporates backtracking to handle wildcards (&#39;.&#39;) by exploring all possible paths.</p>
</li>
<li><p><strong>Recursive Search</strong>: A helper function <code>searchInNode</code> is used for recursive searching with wildcard support.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Designing a word dictionary with add and search functionalities, especially handling wildcard searches, is an engaging exercise in Trie data structures and backtracking algorithms.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-design-add-and-search-words-data-structure</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-design-add-and-search-words-data-structure</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Lowest Common Ancestor of a Binary Search Tree: Finding a Common Node]]></title>
            <description><![CDATA[<p>The &quot;Lowest Common Ancestor of a Binary Search Tree&quot; problem focuses on finding the lowest (or deepest) common ancestor of two nodes in a BST. The lowest common ancestor is defined as the lowest node in the tree that has both nodes as descendants.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.</p>
<h2 id="example">Example</h2>
<p>Consider a binary search tree:<br><img src="/assets/blind-75/235.lowest_common_ancestor_of_a_binary_search_tree/binarysearchtree_improved.png" alt="Binary Search Tree"></p>
<p>The lowest common ancestor of nodes <code>2</code> and <code>8</code> is <code>6</code>.</p>
<h2 id="solution-approach---iterative-traversal">Solution Approach - Iterative Traversal</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function lowestCommonAncestor(root: TreeNode | null, p: TreeNode, q: TreeNode): TreeNode | null {
    let currentNode = root;

    while (currentNode) {
        if (p.val &lt; currentNode.val &amp;&amp; q.val &lt; currentNode.val) {
            currentNode = currentNode.left;
        } else if (p.val &gt; currentNode.val &amp;&amp; q.val &gt; currentNode.val) {
            currentNode = currentNode.right;
        } else {
            return currentNode;
        }
    }

    return null;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Iterative Search</strong>: Iteratively traverse the tree starting from the root.</p>
</li>
<li><p><strong>Decision Making</strong>: If both nodes <code>p</code> and <code>q</code> are smaller than the current node, move to the left subtree. If both are larger, move to the right subtree.</p>
</li>
<li><p><strong>Finding LCA</strong>: The first node where <code>p</code> and <code>q</code> split into different directions is the LCA.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Finding the Lowest Common Ancestor in a BST is a fundamental problem in tree algorithms, demonstrating the efficiency of BST properties in solving search-related queries.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-lowest-common-ancestor-of-bst</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-lowest-common-ancestor-of-bst</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Construct Binary Tree from Preorder and Inorder Traversal]]></title>
            <description><![CDATA[<p>The &quot;Construct Binary Tree from Preorder and Inorder Traversal&quot; problem involves rebuilding a binary tree from its preorder and inorder traversal sequences.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two integer arrays <code>preorder</code> and <code>inorder</code> where <code>preorder</code> is the preorder traversal of a binary tree and <code>inorder</code> is the inorder traversal of the same tree, construct and return the binary tree.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Preorder</strong>: <code>[3,9,20,15,7]</code></li>
<li><strong>Inorder</strong>: <code>[9,3,15,20,7]</code></li>
</ul>
<p>The constructed binary tree is:<br><img src="/assets/blind-75/105.construct-binary-tree-from-preorder-and-inorder-traversal/tree.jpg" alt="Binary Tree"></p>
<h2 id="solution-approach---recursive-construction">Solution Approach - Recursive Construction</h2>
<pre><code class="language-typescript">class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = val === undefined ? 0 : val;
    this.left = left === undefined ? null : left;
    this.right = right === undefined ? null : right;
  }
}

function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
  let preIndex = 0;
  const inMap = new Map&lt;number, number&gt;();
  inorder.forEach((val, index) =&gt; inMap.set(val, index));

  function arrayToTree(left: number, right: number): TreeNode | null {
    if (left &gt; right) return null;

    const rootVal = preorder[preIndex++];
    const rootValueIndex = inMap.get(rootVal);

    if (rootValueIndex === undefined) {
      throw new Error(`Key ${rootVal} not found in map.`);
    }

    const root = new TreeNode(rootVal);

    root.left = arrayToTree(left, rootValueIndex - 1);
    root.right = arrayToTree(rootValueIndex + 1, right);

    return root;
  }

  return arrayToTree(0, inorder.length - 1);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Map for Inorder Indices</strong>: Create a map to quickly find the index of each value in the inorder sequence.</p>
</li>
<li><p><strong>Recursive Construction</strong>: Recursively build the left and right subtrees using the indices in the map to find the dividing point.</p>
</li>
<li><p><strong>Preorder Traversal</strong>: The preorder array guides the creation of each node, starting from the root.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Constructing a binary tree from preorder and inorder traversals is an intriguing challenge that tests understanding of tree properties and traversal techniques.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-construct-binary-tree-from-preorder-and-inorder-traversal</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-construct-binary-tree-from-preorder-and-inorder-traversal</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Kth Smallest Element in a BST: Navigating Tree Order]]></title>
            <description><![CDATA[<p>The &quot;Kth Smallest Element in a BST&quot; problem requires finding the kth smallest element in a Binary Search Tree (BST). This problem can be effectively tackled by understanding and utilizing the properties of BSTs, particularly inorder traversal.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary search tree and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.</p>
<h2 id="example">Example</h2>
<p>Consider a binary search tree:<br><strong>Example 1:</strong><br><img src="/assets/blind-75/230.kth_smallest_element_in_a_bst/kthtree1.jpg" alt="Binary Search Tree"></p>
<p>Input: root = [3,1,4,null,2], k = 1<br>Output: 1</p>
<p><strong>Example 2:</strong><br><img src="/assets/blind-75/230.kth_smallest_element_in_a_bst/kthtree2.jpg" alt="Binary Search Tree"></p>
<p>Input: root = [5,3,6,2,4,null,null,1], k = 3<br>Output: 3</p>
<h2 id="solution-approach---inorder-traversal">Solution Approach - Inorder Traversal</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function kthSmallest(root: TreeNode | null, k: number): number {
  const stack: TreeNode[] = [];
  let current = root;
  let count = 0;

  while (current || stack.length &gt; 0) {
    while (current) {
      stack.push(current);
      current = current.left;
    }

    let poppedValue = stack.pop();

    if (poppedValue !== undefined) {
      current = poppedValue;
      count++;
      if (count === k) return current.val;

      current = current.right;
    } else {
      current = null; // or however you want to handle the undefined case
    }
  }

  return -1;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Map for Inorder Indices</strong>: Create a map to quickly find the index of each value in the inorder sequence.</p>
</li>
<li><p><strong>Recursive Construction</strong>: Recursively build the left and right subtrees using the indices in the map to find the dividing point.</p>
</li>
<li><p><strong>Preorder Traversal</strong>: The preorder array guides the creation of each node, starting from the root.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Constructing a binary tree from preorder and inorder traversals is an intriguing challenge that tests understanding of tree properties and traversal techniques.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-kth-smallest-element-in-a-bst</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-kth-smallest-element-in-a-bst</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Serialize and Deserialize Binary Tree: Encoding and Reconstructing Trees]]></title>
            <description><![CDATA[<p>The &quot;Serialize and Deserialize Binary Tree&quot; problem is about finding efficient ways to convert a binary tree into a string format (serialize) and then reconstruct the tree from that string (deserialize).</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary tree, design an algorithm to serialize the tree into a string and deserialize the string back into the original tree structure.</p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:<br><img src="/assets/blind-75/297.serialize-and-deserialize-binary-tree/serdeser.jpg" alt="Binary Tree"></p>
<p>Serialized string might be: <code>&quot;1,2,null,null,3,4,null,null,5,null,null&quot;</code></p>
<h2 id="solution-approach---depth-first-traversal">Solution Approach - Depth-First Traversal</h2>
<pre><code class="language-typescript">class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = val === undefined ? 0 : val;
    this.left = left === undefined ? null : left;
    this.right = right === undefined ? null : right;
  }
}

function serialize(root: TreeNode | null): string {
  return serializeHelper(root, []).join();

  function serializeHelper(node: TreeNode | null, arr: string[]): string[] {
    if (node === null) {
      arr.push(&#39;null&#39;);
    } else {
      arr.push(node.val.toString());
      serializeHelper(node.left, arr);
      serializeHelper(node.right, arr);
    }
    return arr;
  }
}

function deserialize(data: string): TreeNode | null {
  const arr = data.split(&#39;,&#39;);
  return deserializeHelper(arr);

  function deserializeHelper(arr: string[]): TreeNode | null {
    if (arr[0] === &#39;null&#39;) {
      arr.shift();
      return null;
    }

    const value = arr.shift();
    if (typeof value === &#39;string&#39;) {
      const root = new TreeNode(parseInt(value));
      root.left = deserializeHelper(arr);
      root.right = deserializeHelper(arr);
      return root;
    } else {
      throw new Error(&#39;Array is empty, cannot shift any more elements.&#39;);
    }
    
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Serialize Function</strong>: Convert the tree into a string representation using pre-order traversal.</p>
</li>
<li><p><strong>Deserialize Function</strong>: Reconstruct the tree from the string representation, again using pre-order traversal logic.</p>
</li>
<li><p><strong>Handling Null Nodes</strong>: &#39;null&#39; is used to represent the absence of a node.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Serializing and deserializing a binary tree is a critical problem in tree algorithms, demonstrating the importance of tree traversal techniques and data representation in computing.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-serialize-and-deserialize-binary-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-serialize-and-deserialize-binary-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 20 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Validate Binary Search Tree: Ensuring Proper Order]]></title>
            <description><![CDATA[<p>The &quot;Validate Binary Search Tree&quot; problem involves checking whether a binary tree meets the criteria of a binary search tree (BST). In a BST, the left subtree of a node contains only nodes with keys lesser than the node&#39;s key, and the right subtree only nodes with keys greater.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary tree, determine if it is a valid binary search tree (BST).</p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:<br><img src="/assets/blind-75/98.validate-binary-search-tree/tree1.jpg" alt="Binary Tree"></p>
<p>This tree is a valid BST.</p>
<h2 id="solution-approach---recursive-traversal">Solution Approach - Recursive Traversal</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function isValidBST(root: TreeNode | null): boolean {
    return validate(root, null, null);

    function validate(node: TreeNode | null, low: number | null, high: number | null): boolean {
        if (node === null) return true;
        if ((low !== null &amp;&amp; node.val &lt;= low) || (high !== null &amp;&amp; node.val &gt;= high)) return false;
        return validate(node.left, low, node.val) &amp;&amp; validate(node.right, node.val, high);
    }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Strategy</strong>: The function <code>validate</code> recursively checks each node.</p>
</li>
<li><p><strong>Boundary Conditions</strong>: Each node&#39;s value is compared against the allowed range (low and high) determined by its ancestors.</p>
</li>
<li><p><strong>Left and Right Subtree Checks</strong>: Ensures that left child values are less than the node&#39;s value and right child values are greater.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Validating a binary search tree is a fundamental problem in tree algorithms, highlighting the importance of recursion and boundary conditions in tree traversal.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-validate-binary-search-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-validate-binary-search-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 19 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Subtree of Another Tree: Comparing Tree Structures]]></title>
            <description><![CDATA[<p>The &quot;Subtree of Another Tree&quot; problem involves determining whether one binary tree is a subtree of another binary tree.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two non-empty binary trees <code>s</code> and <code>t</code>, check whether tree <code>t</code> has exactly the same structure and node values with a subtree of tree <code>s</code>.</p>
<h2 id="example">Example</h2>
<p>Consider two binary trees <code>s</code> and <code>t</code>:<br><img src="/assets/blind-75/572.subtree-of-another-tree/subtree1-tree.jpg" alt="Two binary trees"></p>
<p>Tree <code>t</code> is a subtree of tree <code>s</code>.</p>
<h2 id="solution-approach---recursive-comparison">Solution Approach - Recursive Comparison</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function isSubtree(s: TreeNode | null, t: TreeNode | null): boolean {
    if (!s) return !t;
    return isSameTree(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
}

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
    if (!p || !q) return p === q;
    if (p.val !== q.val) return false;
    return isSameTree(p.left, q.left) &amp;&amp; isSameTree(p.right, q.right);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Tree Comparison</strong>: The function <code>isSameTree</code> checks if two trees are identical.</p>
</li>
<li><p><strong>Subtree Check</strong>: The function <code>isSubtree</code> checks if <code>t</code> is the same as <code>s</code>, or if <code>t</code> is a subtree of either the left or right subtree of <code>s</code>.</p>
</li>
<li><p><strong>Base Cases</strong>: Handle null trees appropriately in both functions.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Subtree of Another Tree problem is an interesting application of binary tree algorithms, requiring a combination of tree traversal and recursive comparison to determine subtree relationships.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-subtree-of-another-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-subtree-of-another-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Tue, 16 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Binary Tree Level Order Traversal: Navigating Trees by Level]]></title>
            <description><![CDATA[<p>The &quot;Binary Tree Level Order Traversal&quot; problem involves traversing a binary tree level by level, collecting nodes at each level in separate lists.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary tree, return the level order traversal of its nodes&#39; values. (i.e., from left to right, level by level).</p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:<br><img src="/assets/blind-75/102.binary-tree-level-order-traversal/tree1.jpg" alt="Binary Tree"></p>
<p>Level order traversal of this tree is <code>[[3], [9,20], [15,7]]</code>.</p>
<h2 id="solution-approach---queue-based-traversal">Solution Approach - Queue-Based Traversal</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function levelOrder(root: TreeNode | null): number[][] {
    if (!root) return [];
    
    const result: number[][] = [];
    const queue: TreeNode[] = [root];

    while (queue.length) {
        const levelSize = queue.length;
        const currentLevel: number[] = [];

        for (let i = 0; i &lt; levelSize; i++) {
            const node = queue.shift();
            if (node) {
                currentLevel.push(node.val);
                if (node.left) queue.push(node.left);
                if (node.right) queue.push(node.right);
            }
        }

        result.push(currentLevel);
    }

    return result;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Queue Mechanism</strong>: Use a queue to keep track of nodes at each level.</p>
</li>
<li><p><strong>Iterative Traversal</strong>: Iteratively process nodes in the queue, adding their children to the queue for the next level.</p>
</li>
<li><p><strong>Collecting Levels</strong>: Collect the values of nodes at each level in separate lists.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Binary Tree Level Order Traversal is a fundamental problem in tree algorithms, emphasizing breadth-first traversal and demonstrating the practical use of queues in managing hierarchical data structures.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-binary-tree-level-order-traversal</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-binary-tree-level-order-traversal</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sun, 14 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Invert Binary Tree: Flipping a Binary Tree]]></title>
            <description><![CDATA[<p>The &quot;Invert Binary Tree&quot; problem focuses on inverting a binary tree, effectively flipping it around its center, such that each left child becomes a right child and vice versa.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary tree, invert the tree, and return its root. </p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:<br><img src="/assets/blind-75/226.invert-binary-tree/invert1-tree.jpg" alt="Binary Tree"></p>
<p>The inverted tree is a mirror image of the original tree.</p>
<h2 id="solution-approach---recursive-swap">Solution Approach - Recursive Swap</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function invertTree(root: TreeNode | null): TreeNode | null {
    if (root === null) {
        return null;
    }
    [root.left, root.right] = [invertTree(root.right), invertTree(root.left)];
    return root;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Approach</strong>: The function <code>invertTree</code> is a recursive solution that inverts each node in the tree.</p>
</li>
<li><p><strong>Swapping Children</strong>: At each node, swap its left and right children.</p>
</li>
<li><p><strong>Base Case</strong>: If a node is null, return null.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Inverting a binary tree is an interesting problem that demonstrates the elegance and simplicity of recursive tree manipulation, showcasing fundamental concepts in binary tree algorithms.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-invert-binary-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-invert-binary-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sun, 14 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Group Anagrams: Categorizing Words by Character Composition]]></title>
            <description><![CDATA[<p>The &quot;Group Anagrams&quot; problem involves categorizing a list of strings into groups, where each group contains words that are anagrams of each other.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of strings, group the anagrams together. An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>[&quot;eat&quot;, &quot;tea&quot;, &quot;tan&quot;, &quot;ate&quot;, &quot;nat&quot;, &quot;bat&quot;]</code></li>
<li><strong>Output</strong>: <code>[[&quot;ate&quot;,&quot;eat&quot;,&quot;tea&quot;], [&quot;nat&quot;,&quot;tan&quot;], [&quot;bat&quot;]]</code></li>
</ul>
<h2 id="solution-approach---hashing-and-sorting">Solution Approach - Hashing and Sorting</h2>
<pre><code class="language-javascript">function groupAnagrams(strs) {
    let map = {};

    for (let str of strs) {
        let sortedStr = str.split(&#39;&#39;).sort().join(&#39;&#39;);
        if (!map[sortedStr]) {
            map[sortedStr] = [];
        }
        map[sortedStr].push(str);
    }

    return Object.values(map);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Sort and Hash</strong>: For each string, sort its characters and use the sorted string as a key in a map.</p>
</li>
<li><p><strong>Group Anagrams</strong>: Group the original strings by their sorted key in the map.</p>
</li>
<li><p><strong>Result</strong>: Return the grouped anagrams as an array of arrays.</p>
</li>
</ul>
<h2 id="solution-in-typescript">Solution in Typescript</h2>
<pre><code class="language-typescript">function groupAnagrams(strs: string[]): string[][] {
    const map: Record&lt;string, string[]&gt; = {};

    for (const str of strs) {
        // Sort each string to form the key
        const sortedStr = str.split(&#39;&#39;).sort().join(&#39;&#39;);
        // Group strings by their sorted key
        if (!map[sortedStr]) {
            map[sortedStr] = [];
        }
        map[sortedStr].push(str);
    }

    // Return the grouped anagrams
    return Object.values(map);
}
</code></pre>
<p>In this TypeScript solution:</p>
<ul>
<li>The function <code>groupAnagrams</code> takes an array of strings.</li>
<li>A map (<code>Record&lt;string, string[]&gt;</code>) is used to group strings by their sorted form.</li>
<li>Each string in the input array is split into characters, sorted, and then joined back to form a key.</li>
<li>The original strings are then grouped in the map based on this key.</li>
<li>Finally, the function returns the values of the map, which are arrays of anagrams.</li>
</ul>
<p>This implementation effectively groups anagrams together by using the sorted version of each string as a key, ensuring that all anagrams have the same key and are thus grouped together.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Group Anagrams problem is an interesting exercise in string manipulation, sorting, and hashing. It demonstrates how to categorize data based on shared characteristics, in this case, the composition of characters.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-group-anagrams</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-group-anagrams</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Palindromic Substring: Identifying Maximum Symmetry]]></title>
            <description><![CDATA[<p>The &quot;Longest Palindromic Substring&quot; problem involves finding the longest contiguous substring within a given string that is a palindrome.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string <code>s</code>, return the longest palindromic substring in <code>s</code>. A palindrome is a sequence of characters that reads the same forward and backward.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>&quot;babad&quot;</code></li>
<li><strong>Output</strong>: <code>&quot;bab&quot;</code> (Note: <code>&quot;aba&quot;</code> is also a valid answer)</li>
</ul>
<h2 id="solution-approach---expand-around-center">Solution Approach - Expand Around Center</h2>
<pre><code class="language-typescript">function longestPalindrome(s: string): string {
    if (!s || s.length &lt; 2) return s;

    let start = 0, end = 0;
    for (let i = 0; i &lt; s.length; i++) {
        let len1 = expandAroundCenter(s, i, i);       // Odd length palindrome
        let len2 = expandAroundCenter(s, i, i + 1);   // Even length palindrome
        let len = Math.max(len1, len2);
        if (len &gt; end - start) {
            start = i - Math.floor((len - 1) / 2);
            end = i + Math.floor(len / 2);
        }
    }
    return s.substring(start, end + 1);
}

function expandAroundCenter(s: string, left: number, right: number): number {
    while (left &gt;= 0 &amp;&amp; right &lt; s.length &amp;&amp; s[left] === s[right]) {
        left--;
        right++;
    }
    return right - left - 1;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Center Expansion Technique</strong>: For each character in <code>s</code>, expand around it to find the longest palindrome.</p>
</li>
<li><p><strong>Handle Even and Odd Length</strong>: Check for palindromes of both odd and even lengths.</p>
</li>
<li><p><strong>Update Maximum Bounds</strong>: Update the start and end indices of the longest palindrome found.</p>
</li>
</ul>
<h2 id="solution-in-typescript">Solution in typescript</h2>
<pre><code class="language-typescript">function longestPalindrome(s: string): string {
  if (s.length &lt; 2) return s;

  let start = 0,
    maxLength = 1;

  for (let i = 0; i &lt; s.length; i++) {
    expandAroundCenter(s, i, i); // Odd length palindrome
    expandAroundCenter(s, i, i + 1); // Even length palindrome
  }

  function expandAroundCenter(str: string, left: number, right: number) {
    while (left &gt;= 0 &amp;&amp; right &lt; str.length &amp;&amp; str[left] === str[right]) {
      if (right - left + 1 &gt; maxLength) {
        start = left;
        maxLength = right - left + 1;
      }
      left--;
      right++;
    }
  }

  return s.substring(start, start + maxLength);
}
</code></pre>
<p>In this TypeScript solution:</p>
<ul>
<li>The function <code>longestPalindrome</code> takes a string <code>s</code> as input.</li>
<li>Two pointers (<code>left</code> and <code>right</code>) are used to expand around each character in the string to check for palindromes.</li>
<li>The function <code>expandAroundCenter</code> expands around the center (the current character for odd length and between the current and next character for even length) and updates the start and maxLength if a longer palindrome is found.</li>
<li>The <code>substring</code> method is used to extract and return the longest palindromic substring.</li>
</ul>
<p>This approach effectively finds the longest palindromic substring by checking each character as the center of potential odd and even length palindromes.</p>
<p>The two-pointers approach for finding the longest palindromic substring is already quite efficient, particularly for its simplicity and directness in handling the problem. However, there are a couple of strategies that can be applied to optimize this solution further:</p>
<ol>
<li><p><strong>Early Termination</strong>: If the remaining substring is shorter than the current longest palindrome found, you can stop the search. This optimization helps reduce the number of unnecessary expansions.</p>
</li>
<li><p><strong>Skip Identical Characters</strong>: When expanding around the center, if you encounter a group of identical characters, you can skip them in one step instead of expanding one character at a time. This can speed up the search in cases where there are long runs of the same character.</p>
</li>
</ol>
<p>Here&#39;s how you could implement these optimizations:</p>
<pre><code class="language-typescript">function longestPalindrome(s: string): string {
    if (s.length &lt; 2) return s;

    let start = 0, maxLength = 1;

    for (let i = 0; i &lt; s.length; i++) {
        if (s.length - i &lt;= maxLength / 2) break; // Early termination
        expandAroundCenter(s, i, i); // Odd length palindrome
        expandAroundCenter(s, i, i + 1); // Even length palindrome
    }

    function expandAroundCenter(str: string, left: number, right: number) {
        while (left &gt;= 0 &amp;&amp; right &lt; str.length &amp;&amp; str[left] === str[right]) {
            left--;
            right++;
        }
        // Adjust left and right to the last valid palindrome
        left++; right--;

        if (right - left + 1 &gt; maxLength) {
            start = left;
            maxLength = right - left + 1;
        }
    }

    return s.substring(start, start + maxLength);
}
</code></pre>
<p>These optimizations can improve performance in specific scenarios, especially for longer strings or strings with many repeated characters. However, the fundamental time complexity of the algorithm remains O(n^2), as it still needs to consider each character as a potential center of a palindrome.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Longest Palindromic Substring problem is a fascinating challenge in string processing, showcasing techniques like center expansion to find symmetrical patterns in text.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-palindromic-substring</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-palindromic-substring</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Repeating Character Replacement: Maximizing Repeating Sequences]]></title>
            <description><![CDATA[<p>The &quot;Longest Repeating Character Replacement&quot; problem involves finding the longest repeating character sequence in a string by replacing a limited number of characters.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string <code>s</code> and an integer <code>k</code>, return the length of the longest substring containing the same letter you can get after performing at most <code>k</code> character replacements.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>s = &quot;AABABBA&quot;, k = 1</code></li>
<li><strong>Output</strong>: <code>4</code> (Replace the one &#39;B&#39; in &quot;AABABBA&quot; with &#39;A&#39; to get &quot;AAAA&quot;)</li>
</ul>
<h2 id="solution-approach---sliding-window-technique-typescript">Solution Approach - Sliding Window Technique (typescript)</h2>
<pre><code class="language-typescript">export function characterReplacement(s: string, k: number): number {
  let count: Record&lt;string, number&gt; = {};
  let maxCount = 0,
    maxLength = 0,
    start = 0;

  for (let end = 0; end &lt; s.length; end++) {
    count[s[end]] = (count[s[end]] || 0) + 1;
    maxCount = Math.max(maxCount, count[s[end]]);

    while (end - start + 1 - maxCount &gt; k) {
      count[s[start]]--;
      start++;
    }

    maxLength = Math.max(maxLength, end - start + 1);
  }

  return maxLength;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Sliding Window</strong>: Maintain a window of characters using two pointers (<code>start</code> and <code>end</code>).</p>
</li>
<li><p><strong>Track Character Counts</strong>: Use a map to count the occurrences of each character within the window.</p>
</li>
<li><p><strong>Adjust Window</strong>: If the window size minus the count of the most frequent character exceeds <code>k</code>, shrink the window from the start.</p>
</li>
<li><p><strong>Calculate Max Length</strong>: Update the maximum length of the substring as the window slides.</p>
</li>
</ul>
<p>Imagine you have a long string of colorful beads, and each bead has a letter on it. Now, your task is to make the longest string of beads where all the beads have the same letter. But, there&#39;s a catch! You can only change a few beads (let&#39;s say <code>k</code> beads) to match the other beads.</p>
<p>Here&#39;s how you can do it:</p>
<ol>
<li><p><strong>Start Making a Necklace</strong>: Start stringing the beads together from one end. Keep adding beads as long as they have the same letter or until you have changed <code>k</code> beads to match.</p>
</li>
<li><p><strong>Remember the Longest Necklace</strong>: As you string the beads, remember the longest necklace you&#39;ve made so far where all beads looked the same.</p>
</li>
<li><p><strong>Can&#39;t Change More Beads?</strong>: If you need to change more than <code>k</code> beads to keep adding to your necklace, then stop. Maybe start again from a different bead.</p>
</li>
<li><p><strong>Try Different Starting Points</strong>: Keep trying to start your necklace from different beads in the string, using your <code>k</code> chances to change beads that don&#39;t match.</p>
</li>
<li><p><strong>Find the Longest Necklace</strong>: After trying different starting points and using your <code>k</code> chances in the best way, the longest necklace you made is your answer!</p>
</li>
</ol>
<p>In this game, changing a bead means replacing a character in the string, and making the longest necklace of the same letter is like finding the longest substring where you can replace at most k characters to make all characters in that substring the same.</p>
<h2 id="video-explanation">Video Explanation</h2>
<p><a href="https://www.youtube.com/watch?v=gqXU1UyA8pk" target="_blank" rel="noopener noreferrer">Longest Repeating Character Replacement</a></p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Longest Repeating Character Replacement problem is an interesting challenge that tests the sliding window technique in strings. It&#39;s a valuable exercise in balancing the frequency of characters with the allowed number of replacements.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-repeating-character-replacement</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-repeating-character-replacement</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Maximum Depth of Binary Tree: Finding the Longest Path]]></title>
            <description><![CDATA[<p>The &quot;Maximum Depth of Binary Tree&quot; problem is focused on finding the maximum depth (or height) of a binary tree. The depth of a binary tree is the number of nodes along the longest path from the root node down to the farthest leaf node.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the root of a binary tree, return its maximum depth.</p>
<h2 id="example">Example</h2>
<p>Consider a binary tree:</p>
<p><img src="/assets/blind-75/104.maximum-depth-of-binary-tree/tmp-tree.jpg" alt="Binary Tree"></p>
<p>The maximum depth of this tree is <code>3</code>.</p>
<h2 id="solution-approach---depth-first-search">Solution Approach - Depth-First Search</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function maxDepth(root: TreeNode | null): number {
    if (root === null) {
        return 0;
    } else {
        let leftDepth = maxDepth(root.left);
        let rightDepth = maxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Approach</strong>: The solution uses a recursive depth-first search algorithm.</p>
</li>
<li><p><strong>Base Case</strong>: If the node is <code>null</code>, the depth is <code>0</code>.</p>
</li>
<li><p><strong>Recursive Calculation</strong>: The depth of each subtree (left and right) is calculated, and the greater of the two depths is chosen, adding one to account for the current node.</p>
</li>
</ul>
<h2 id="solution-in-typescript-one-liner">Solution in Typescript one-liner</h2>
<pre><code class="language-typescript">function maxDepth(root: TreeNode | null): number {
    if(!root) return 0;
    
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
};
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>Determining the maximum depth of a binary tree is a fundamental problem in tree algorithms, emphasizing the use of recursion and understanding of tree traversal techniques.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-maximum-depth-of-binary-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-maximum-depth-of-binary-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Minimum Window Substring: Finding the Smallest Containing Segment]]></title>
            <description><![CDATA[<p>The &quot;Minimum Window Substring&quot; problem is about finding the smallest substring within a larger string that contains all the characters of a target string.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two strings <code>s</code> and <code>t</code>, return the minimum window in <code>s</code> which will contain all the characters in <code>t</code>. If there is no such window in <code>s</code> that covers all characters in <code>t</code>, return the empty string <code>&quot;&quot;</code>.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>s = &quot;ADOBECODEBANC&quot;, t = &quot;ABC&quot;</code></li>
<li><strong>Output</strong>: <code>&quot;BANC&quot;</code></li>
</ul>
<h2 id="solution-approach---sliding-window-technique-javascript">Solution Approach - Sliding Window Technique (javascript)</h2>
<pre><code class="language-javascript">function minWindow(s, t) {
    let map = {};
    t.split(&#39;&#39;).forEach(char =&gt; map[char] = (map[char] || 0) + 1);

    let counter = Object.keys(map).length;
    let begin = 0, end = 0, head = 0;
    let minLength = Infinity;

    while (end &lt; s.length) {
        let endChar = s[end];
        if (map[endChar] !== undefined) map[endChar]--;
        if (map[endChar] === 0) counter--;

        while (counter === 0) {
            let tempLength = end - begin + 1;
            if (tempLength &lt; minLength) {
                minLength = tempLength;
                head = begin;
            }

            let startChar = s[begin];
            if (map[startChar] !== undefined) map[startChar]++;
            if (map[startChar] &gt; 0) counter++;

            begin++;
        }

        end++;
    }

    return minLength === Infinity ? &quot;&quot; : s.substr(head, minLength);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Character Count Map</strong>: Create a map to count the occurrences of each character in <code>t</code>.</p>
</li>
<li><p><strong>Sliding Window</strong>: Move a window over <code>s</code>, expanding and contracting it while tracking character frequencies.</p>
</li>
<li><p><strong>Find Minimum Window</strong>: When all characters from <code>t</code> are in the current window, try to minimize the window size while maintaining all characters from <code>t</code>.</p>
</li>
</ul>
<h2 id="solution-in-typescript">Solution in typescript</h2>
<pre><code class="language-typescript">function minWindow(s: string, t: string): string {
    let charMap: { [key: string]: number } = {};
    t.split(&#39;&#39;).forEach(char =&gt; {
        charMap[char] = (charMap[char] || 0) + 1;
    });

    let start = 0, end = 0, minLength = Infinity, head = 0;
    let required = Object.keys(charMap).length;

    while (end &lt; s.length) {
        let endChar = s[end];
        if (charMap[endChar] !== undefined) charMap[endChar]--;
        if (charMap[endChar] === 0) required--;

        while (required === 0) {
            let tempLength = end - start + 1;
            if (tempLength &lt; minLength) {
                minLength = tempLength;
                head = start;
            }

            let startChar = s[start];
            if (charMap[startChar] !== undefined) charMap[startChar]++;
            if (charMap[startChar] &gt; 0) required++;

            start++;
        }

        end++;
    }

    return minLength === Infinity ? &quot;&quot; : s.substring(head, head + minLength);
}
</code></pre>
<p>In this TypeScript implementation:</p>
<ul>
<li>The <code>minWindow</code> function takes two strings <code>s</code> (the source string) and <code>t</code> (the target string).</li>
<li>A map <code>charMap</code> is used to keep count of the required characters from <code>t</code>.</li>
<li>The sliding window is defined by two pointers, <code>start</code> and <code>end</code>, which traverse the string <code>s</code>.</li>
<li>When all required characters are within the current window, the window is contracted from the start to find the minimum length window that contains all characters of <code>t</code>.</li>
<li>The <code>minLength</code> and <code>head</code> variables keep track of the size and starting position of the smallest valid window.</li>
<li>The function returns the substring of <code>s</code> that represents the minimum window, or an empty string if no such window exists.</li>
</ul>
<p>You can run this TypeScript code to find the smallest window in string <code>s</code> that contains all characters from string <code>t</code>.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Minimum Window Substring problem is a key challenge in string manipulation, testing the ability to apply the sliding window technique effectively. It&#39;s commonly used in interview settings for its complexity and practical relevance in text processing.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-minimum-window-substring</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-minimum-window-substring</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Palindromic Substrings: Counting Symmetrical Sequences]]></title>
            <description><![CDATA[<p>The &quot;Palindromic Substrings&quot; problem involves identifying and counting all the substrings within a given string that are palindromes.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string <code>s</code>, return the number of palindromic substrings in it. A substring is palindromic if it reads the same forward and backward.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>&quot;abc&quot;</code></li>
<li><strong>Output</strong>: <code>3</code> (The palindromic substrings are: <code>&quot;a&quot;</code>, <code>&quot;b&quot;</code>, <code>&quot;c&quot;</code>)</li>
<li><strong>Input</strong>: <code>&quot;aaa&quot;</code></li>
<li><strong>Output</strong>: <code>6</code> (The palindromic substrings are: <code>&quot;a&quot;</code>, <code>&quot;a&quot;</code>, <code>&quot;a&quot;</code>, <code>&quot;aa&quot;</code>, <code>&quot;aa&quot;</code>, <code>&quot;aaa&quot;</code>)</li>
</ul>
<h2 id="solution-approach---expand-around-center">Solution Approach - Expand Around Center</h2>
<pre><code class="language-typescript">function countSubstrings(s: string): number {
    let count = 0;

    for (let i = 0; i &lt; s.length; i++) {
        count += expandAroundCenter(s, i, i);       // Odd length palindromes
        count += expandAroundCenter(s, i, i + 1);   // Even length palindromes
    }

    function expandAroundCenter(str: string, left: number, right: number): number {
        let tempCount = 0;
        while (left &gt;= 0 &amp;&amp; right &lt; str.length &amp;&amp; str[left] === str[right]) {
            tempCount++;
            left--;
            right++;
        }
        return tempCount;
    }

    return count;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Center Expansion Technique</strong>: For each character, consider it as the center of potential odd and even length palindromes.</p>
</li>
<li><p><strong>Counting Palindromes</strong>: Expand around each center and count valid palindromic substrings.</p>
</li>
<li><p><strong>Iterative Process</strong>: Accumulate the count of palindromic substrings for each expansion.</p>
</li>
</ul>
<h2 id="optimised-solution">Optimised solution</h2>
<pre><code class="language-typescript">function countSubstrings(s: string): number {
    let count = 0;

    for (let i = 0; i &lt; s.length; i++) {
        // Check for odd length palindromes
        count += countPalindromesAroundCenter(s, i, i);
        // Check for even length palindromes
        count += countPalindromesAroundCenter(s, i, i + 1);
    }

    return count;
}

function countPalindromesAroundCenter(s: string, left: number, right: number): number {
    let count = 0;
    while (left &gt;= 0 &amp;&amp; right &lt; s.length &amp;&amp; s[left] === s[right]) {
        count++; // Increment count for each palindrome found
        left--;  // Expand to the left
        right++; // Expand to the right
    }
    return count;
}
</code></pre>
<h3 id="optimizations">Optimizations:</h3>
<ol>
<li><p><strong>Focused Function</strong>: The <code>countPalindromesAroundCenter</code> function is dedicated solely to counting palindromic substrings, making the code more modular and easier to understand.</p>
</li>
<li><p><strong>Single Responsibility</strong>: Each call to <code>countPalindromesAroundCenter</code> checks either odd or even length palindromes. This separation makes it clear what each function call is responsible for.</p>
</li>
<li><p><strong>Efficient Expansion</strong>: The function expands around the center only as long as it finds palindromic substrings, minimizing unnecessary checks.</p>
</li>
</ol>
<p>This approach retains the O(n^2) complexity, as in the worst case (like a string of identical characters), it must still expand around each character. However, it&#39;s more efficient in terms of operations performed for each expansion.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Palindromic Substrings problem is a compelling challenge in string processing, demonstrating a methodical approach to identify and count symmetric patterns within a string.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-palindromic-substrings</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-palindromic-substrings</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving Same Tree: Comparing Binary Tree Structures]]></title>
            <description><![CDATA[<p>The &quot;Same Tree&quot; problem is about determining whether two binary trees are structurally identical and have the same node values.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the roots of two binary trees <code>p</code> and <code>q</code>, write a function to check if they are the same or not. Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.</p>
<h2 id="example">Example</h2>
<p>Consider two binary trees:<br><img src="/assets/blind-75/100.same-tree/ex1.jpg" alt="Same Tree Example"></p>
<p>These two trees are the same.</p>
<h2 id="solution-approach---recursive-comparison">Solution Approach - Recursive Comparison</h2>
<pre><code class="language-typescript">class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.left = (left === undefined ? null : left);
        this.right = (right === undefined ? null : right);
    }
}

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
    if (p === null &amp;&amp; q === null) {
        return true;
    }
    if (p === null || q === null) {
        return false;
    }
    if (p.val !== q.val) {
        return false;
    }
    return isSameTree(p.left, q.left) &amp;&amp; isSameTree(p.right, q.right);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Recursive Strategy</strong>: The solution uses recursion to compare corresponding nodes of the two trees.</p>
</li>
<li><p><strong>Base Cases</strong>: Check for null nodes. If both are null, they are the same; if only one is null, they are not the same.</p>
</li>
<li><p><strong>Value Comparison</strong>: Compare the value of the current nodes. If they are different, the trees are not the same.</p>
</li>
<li><p><strong>Recursive Calls</strong>: Recursively compare left and right children of the current nodes.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Same Tree problem is a fundamental exercise in understanding binary tree structure and recursion, highlighting the importance of simultaneous traversal in tree comparison.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-same-tree</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-same-tree</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Valid Anagram: Checking Character Arrangements]]></title>
            <description><![CDATA[<p>The &quot;Valid Anagram&quot; problem involves determining whether two strings are anagrams of each other, meaning they are made of the same characters, just in a different order.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two strings <code>s</code> and <code>t</code>, write a function to determine if <code>t</code> is an anagram of <code>s</code>.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>s = &quot;anagram&quot;, t = &quot;nagaram&quot;</code></li>
<li><strong>Output</strong>: <code>true</code></li>
</ul>
<h2 id="solution-approach---character-counting-javascript">Solution Approach - Character Counting (javascript)</h2>
<pre><code class="language-javascript">function isAnagram(s, t) {
    if (s.length !== t.length) return false;

    let count = {};
    for (let char of s) {
        count[char] = (count[char] || 0) + 1;
    }
    
    for (let char of t) {
        if (!count[char]) return false;
        count[char]--;
    }

    return true;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Length Check</strong>: First, check if <code>s</code> and <code>t</code> are of the same length. If not, they can&#39;t be anagrams.</p>
</li>
<li><p><strong>Count Characters in <code>s</code></strong>: Use a map to count the occurrences of each character in <code>s</code>.</p>
</li>
<li><p><strong>Verify Characters in <code>t</code></strong>: Iterate over <code>t</code> and decrease the count for each character. If a character in <code>t</code> isn&#39;t in <code>s</code> or the count goes below zero, <code>t</code> is not an anagram of <code>s</code>.</p>
</li>
</ul>
<h2 id="solution-in-typescript">Solution in TypeScript</h2>
<pre><code class="language-typescript">function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) {
        return false;
    }

    const count: Record&lt;string, number&gt; = {};
    for (const char of s) {
        count[char] = (count[char] || 0) + 1;
    }

    for (const char of t) {
        if (!count[char]) {
            return false;
        }
        count[char]--;
    }

    return true;
}
</code></pre>
<p>In this TypeScript solution:</p>
<ul>
<li>The function <code>isAnagram</code> takes two strings, <code>s</code> and <code>t</code>, and checks if they are anagrams.</li>
<li>It first compares the lengths of <code>s</code> and <code>t</code>. If they are different, the function returns <code>false</code> immediately.</li>
<li>A record <code>count</code> is used to count the occurrences of each character in <code>s</code>.</li>
<li>Then, the function iterates through <code>t</code>, decrementing the count for each character. If a character in <code>t</code> is not in <code>s</code> or the count drops below zero, <code>t</code> is not an anagram of <code>s</code>.</li>
<li>If all character counts are balanced, the function returns <code>true</code>.</li>
</ul>
<p>This implementation effectively checks whether two strings are anagrams by comparing the frequency of each character in both strings.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Valid Anagram problem is a fundamental exercise in string manipulation and character counting. It&#39;s a simple yet effective way to understand the importance of character frequency and order in strings.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-valid-anagram</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-valid-anagram</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Valid Palindrome: Checking Symmetry in Strings]]></title>
            <description><![CDATA[<p>The &quot;Valid Palindrome&quot; problem focuses on determining whether a given string is a palindrome. A palindrome is a sequence of characters that reads the same forward and backward, typically ignoring spaces, punctuation, and capitalization.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string <code>s</code>, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>&quot;A man, a plan, a canal: Panama&quot;</code></li>
<li><strong>Output</strong>: <code>true</code></li>
<li><strong>Input</strong>: <code>&quot;race a car&quot;</code></li>
<li><strong>Output</strong>: <code>false</code></li>
</ul>
<h2 id="solution-approach---two-pointers-technique-typescript">Solution Approach - Two Pointers Technique (typescript)</h2>
<pre><code class="language-typescript">function isPalindrome(s: string): boolean {
    s = s.replace(/[^A-Za-z0-9]/g, &#39;&#39;).toLowerCase();
    let left = 0, right = s.length - 1;

    while (left &lt; right) {
        if (s[left] !== s[right]) {
            return false;
        }
        left++;
        right--;
    }

    return true;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Preprocessing</strong>: Remove all non-alphanumeric characters and convert to lowercase to standardize the string.</p>
</li>
<li><p><strong>Two Pointers</strong>: Use two pointers, one at the start and one at the end, moving towards the center.</p>
</li>
<li><p><strong>Compare Characters</strong>: If characters at the start and end pointers don&#39;t match, it&#39;s not a palindrome.</p>
</li>
<li><p><strong>Iterate and Validate</strong>: Continue moving pointers inward and comparing until they meet or a mismatch is found.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Valid Palindrome problem is a classic example of using the two pointers technique to check for symmetry in strings. It&#39;s a fundamental exercise in string manipulation and pattern recognition.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-valid-palindrome</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-valid-palindrome</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Valid Parentheses: Ensuring Correct Closure and Nesting]]></title>
            <description><![CDATA[<p>The &quot;Valid Parentheses&quot; problem involves determining whether a string made up of parentheses, brackets, and braces is valid in terms of closure and nesting.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string containing characters &#39;(&#39;, &#39;)&#39;, &#39;{&#39;, &#39;}&#39;, &#39;[&#39; and &#39;]&#39;, determine if the input string is valid. The brackets must close in the correct order, meaning &quot;()&quot; and &quot;()[]{}&quot; are valid, but &quot;(]&quot; and &quot;([)]&quot; are not.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>&quot;()[]{}&quot;</code></li>
<li><strong>Output</strong>: <code>true</code></li>
<li><strong>Input</strong>: <code>&quot;(]&quot;</code></li>
<li><strong>Output</strong>: <code>false</code></li>
</ul>
<h2 id="solution-approach---stack-utilization-typescript">Solution Approach - Stack Utilization (typescript)</h2>
<pre><code class="language-typescript">function isValid(s: string): boolean {
    let stack: string[] = [];
    const mappings = new Map([
        [&#39;)&#39;, &#39;(&#39;],
        [&#39;}&#39;, &#39;{&#39;],
        [&#39;]&#39;, &#39;[&#39;]
    ]);

    for (let char of s) {
        if (mappings.has(char)) {
            const topElement = stack.length === 0 ? &#39;#&#39; : stack.pop();
            if (topElement !== mappings.get(char)) {
                return false;
            }
        } else {
            stack.push(char);
        }
    }

    return stack.length === 0;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Using a Stack</strong>: A stack is used to keep track of opening brackets.</p>
</li>
<li><p><strong>Map for Mappings</strong>: A map holds the pairs of corresponding opening and closing brackets.</p>
</li>
<li><p><strong>Validating Closure</strong>: For each closing bracket, check if the top of the stack is the corresponding opening bracket. If not, the string is invalid.</p>
</li>
<li><p><strong>Empty Stack</strong>: If the stack is empty at the end, the string is valid.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Valid Parentheses problem is a classic example of using a stack to ensure proper closure and nesting of brackets in a string. It&#39;s a fundamental exercise in balancing and ordering in data structures.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-valid-parentheses</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-valid-parentheses</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 13 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Substring Without Repeating Characters: A String Traversal Challenge]]></title>
            <description><![CDATA[<p>The &quot;Longest Substring Without Repeating Characters&quot; problem is a common challenge in string processing, focusing on finding the longest unique substring in a given string.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string, find the length of the longest substring without repeating characters.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>&quot;abcabcbb&quot;</code></li>
<li><strong>Output</strong>: <code>3</code> (The answer is <code>&quot;abc&quot;</code>, with the length of 3)</li>
</ul>
<h2 id="solution-approach---sliding-window-technique">Solution Approach - Sliding Window Technique</h2>
<pre><code class="language-javascript">function lengthOfLongestSubstring(s) {
    let map = new Map();
    let maxLen = 0, start = 0;

    for (let end = 0; end &lt; s.length; end++) {
        if (map.has(s[end])) {
            start = Math.max(start, map.get(s[end]) + 1);
        }
        map.set(s[end], end);
        maxLen = Math.max(maxLen, end - start + 1);
    }

    return maxLen;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Sliding Window</strong>: Use two pointers (<code>start</code> and <code>end</code>) to create a sliding window that expands and contracts as it traverses the string.</p>
</li>
<li><p><strong>Track Characters</strong>: Use a map to track the last index of each character encountered.</p>
</li>
<li><p><strong>Adjust Window</strong>: When a repeated character is found, move the <code>start</code> pointer to avoid the repetition.</p>
</li>
<li><p><strong>Calculate Max Length</strong>: Continuously update the maximum length of the substring as the window slides.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Longest Substring Without Repeating Characters problem is an excellent application of the sliding window technique in strings. It&#39;s commonly used in interview settings to assess understanding of string manipulation and efficient data storage.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-substring-without-repeating-characters</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-substring-without-repeating-characters</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 12 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Rotate Image: 90-Degree Clockwise Transformation]]></title>
            <description><![CDATA[<p>The &quot;Rotate Image&quot; problem involves rotating a 2D matrix (or image) by 90 degrees clockwise in place.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an <code>n x n</code> matrix representing an image, rotate the image by 90 degrees (clockwise). You have to rotate the image in place, which means you have to modify the input 2D matrix directly.</p>
<p><img src="/assets/blind-75/48.rotate-image/mat1.jpg" alt="Rotate Image"><br><img src="/assets/blind-75/48.rotate-image/mat2.jpg" alt="Rotate Image"></p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Matrix</li>
</ul>
<pre><code class="language-json">[
  [1, 2, 3], 
  [4, 5, 6],
  [7, 8, 9]
]
</code></pre>
<ul>
<li><strong>Output</strong> (after rotation):</li>
</ul>
<pre><code class="language-json">[
  [7, 4, 1],
  [8, 5, 2],
  [9, 6, 3]
]
</code></pre>
<h2 id="solution-approach-typescript">Solution Approach (typescript)</h2>
<pre><code class="language-typescript">function rotate(matrix: number[][]): void {
  const n = matrix.length;

  // Transpose the matrix
  for (let i = 0; i &lt; n; i++) {
      for (let j = i; j &lt; n; j++) {
          [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
      }
  }

  // Reverse each row
  for (let i = 0; i &lt; n; i++) {
      matrix[i].reverse();
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Transpose the Matrix</strong>: Swap elements across the diagonal to transpose the matrix, turning rows into columns.</p>
</li>
<li><p><strong>Reverse Each Row</strong>: Reverse the elements in each row to achieve the 90-degree clockwise rotation.</p>
</li>
</ul>
<h2 id="solution-approach-go">Solution Approach (go)</h2>
<pre><code class="language-go">package main

import (
    &quot;fmt&quot;
)

func rotate(matrix [][]int) {
    n := len(matrix)
    // Transpose the matrix
    for i := 0; i &lt; n; i++ {
        for j := i; j &lt; n; j++ {
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        }
    }

    // Reverse each row
    for i := 0; i &lt; n; i++ {
        for j := 0; j &lt; n/2; j++ {
            matrix[i][j], matrix[i][n-1-j] = matrix[i][n-1-j], matrix[i][j]
        }
    }
}

func main() {
    matrix := [][]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }

    rotate(matrix)
    fmt.Println(&quot;Rotated Matrix:&quot;)
    for _, row := range matrix {
        fmt.Println(row)
    }
}
</code></pre>
<p>In this Go program:</p>
<ul>
<li>The <code>rotate</code> function first transposes the matrix by swapping elements across its diagonal.</li>
<li>Then, it reverses each row of the matrix. This combination of transposition and reversal results in a 90-degree clockwise rotation.</li>
<li>The <code>main</code> function demonstrates the usage of the <code>rotate</code> function with a sample matrix.</li>
</ul>
<h2 id="solution-approach-cpp">Solution Approach (cpp)</h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;

void rotate(std::vector&lt;std::vector&lt;int&gt;&gt;&amp; matrix) {
    int n = matrix.size();

    // Transpose the matrix
    for (int i = 0; i &lt; n; ++i) {
        for (int j = i; j &lt; n; ++j) {
            std::swap(matrix[i][j], matrix[j][i]);
        }
    }

    // Reverse each row
    for (int i = 0; i &lt; n; ++i) {
        std::reverse(matrix[i].begin(), matrix[i].end());
    }
}

int main() {
    std::vector&lt;std::vector&lt;int&gt;&gt; matrix = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    rotate(matrix);

    // Output the rotated matrix
    for (const auto&amp; row : matrix) {
        for (int val : row) {
            std::cout &lt;&lt; val &lt;&lt; &quot; &quot;;
        }
        std::cout &lt;&lt; std::endl;
    }

    return 0;
}
</code></pre>
<p>In this solution:</p>
<ul>
<li>The function <code>rotate</code> takes a reference to a 2D vector (representing the matrix) and modifies it in place.</li>
<li>First, the matrix is transposed by swapping elements across the diagonal.</li>
<li>Then, each row of the matrix is reversed. This combination of transposing and reversing the rows results in a 90-degree clockwise rotation.</li>
<li>The <code>main</code> function demonstrates the usage of the <code>rotate</code> function with a sample matrix and prints the rotated matrix.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Rotate Image problem is a classic exercise in matrix manipulation, demonstrating in-place transformations. It&#39;s a practical scenario in image processing and graphical applications, testing one&#39;s understanding of array operations and geometry.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-rotate-image</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-rotate-image</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 12 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Spiral Matrix: Traversing 2D Arrays in a Spiral Pattern]]></title>
            <description><![CDATA[<p>The &quot;Spiral Matrix&quot; problem involves traversing a 2D matrix in a spiral order, starting from the top-left corner and moving clockwise.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a <code>m x n</code> matrix, return all elements of the matrix in spiral order.</p>
<p><img src="/assets/blind-75/spiral1.jpg" alt="Spiral Matrix"><br><img src="/assets/blind-75/spiral.jpg" alt="Spiral Matrix"></p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Matrix</li>
</ul>
<pre><code class="language-json">[
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]
</code></pre>
<ul>
<li><strong>Output</strong>:</li>
</ul>
<pre><code class="language-json">  [1, 2, 3, 6, 9, 8, 7, 4, 5]
</code></pre>
<h2 id="solution-approach-typescript">Solution Approach (typescript)</h2>
<pre><code class="language-typescript">function spiralOrder(matrix: number[][]): number[] {
  if (matrix.length === 0) return [];

  let result: number[] = [];
  let left = 0, right = matrix[0].length - 1;
  let top = 0, bottom = matrix.length - 1;

  while (left &lt;= right &amp;&amp; top &lt;= bottom) {
      for (let i = left; i &lt;= right; i++) result.push(matrix[top][i]);
      top++;

      for (let i = top; i &lt;= bottom; i++) result.push(matrix[i][right]);
      right--;

      if (top &lt;= bottom) {
          for (let i = right; i &gt;= left; i--) result.push(matrix[bottom][i]);
          bottom--;
      }

      if (left &lt;= right) {
          for (let i = bottom; i &gt;= top; i--) result.push(matrix[i][left]);
          left++;
      }
  }

  return result;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize Boundaries</strong>: Start with boundaries (left, right, top, bottom) for the matrix.</p>
</li>
<li><p><strong>Traverse in Spiral</strong>: Move right across the top row, down the rightmost column, left across the bottom row, and up the leftmost column, adjusting boundaries each time.</p>
</li>
<li><p><strong>Continue Inward</strong>: Repeat the process for each layer of the spiral until all elements are covered.</p>
</li>
</ul>
<h2 id="solution-approach-go">Solution Approach (go)</h2>
<pre><code class="language-go">package main

import (
    &quot;fmt&quot;
)

func spiralOrder(matrix [][]int) []int {
    if len(matrix) == 0 {
        return []int{}
    }

    result := make([]int, 0)
    top, bottom := 0, len(matrix)-1
    left, right := 0, len(matrix[0])-1

    for left &lt;= right &amp;&amp; top &lt;= bottom {
        // Move right
        for i := left; i &lt;= right; i++ {
            result = append(result, matrix[top][i])
        }
        top++

        // Move down
        for i := top; i &lt;= bottom; i++ {
            result = append(result, matrix[i][right])
        }
        right--

        if top &lt;= bottom {
            // Move left
            for i := right; i &gt;= left; i-- {
                result = append(result, matrix[bottom][i])
            }
            bottom--
        }

        if left &lt;= right {
            // Move up
            for i := bottom; i &gt;= top; i-- {
                result = append(result, matrix[i][left])
            }
            left++
        }
    }

    return result
}

func main() {
    matrix := [][]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
    fmt.Println(spiralOrder(matrix)) // Output: [1 2 3 6 9 8 7 4 5]
}
</code></pre>
<p>In this Go solution:</p>
<ul>
<li>The function <code>spiralOrder</code> takes a 2D integer slice (<code>matrix</code>) and returns a slice with the elements in spiral order.</li>
<li>The variables <code>top</code>, <code>bottom</code>, <code>left</code>, and <code>right</code> define the boundaries of the current layer of the spiral.</li>
<li>The spiral traversal is performed by moving right, down, left, and up, adjusting the boundaries after each direction change.</li>
<li>The loop continues until all elements are traversed, shrinking the spiral layer by layer.</li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;

std::vector&lt;int&gt; spiralOrder(std::vector&lt;std::vector&lt;int&gt;&gt;&amp; matrix) {
    std::vector&lt;int&gt; result;
    if (matrix.empty()) return result;

    int top = 0, bottom = matrix.size() - 1;
    int left = 0, right = matrix[0].size() - 1;

    while (left &lt;= right &amp;&amp; top &lt;= bottom) {
        // Move right
        for (int i = left; i &lt;= right; i++) {
            result.push_back(matrix[top][i]);
        }
        top++;

        // Move down
        for (int i = top; i &lt;= bottom; i++) {
            result.push_back(matrix[i][right]);
        }
        right--;

        if (top &lt;= bottom) {
            // Move left
            for (int i = right; i &gt;= left; i--) {
                result.push_back(matrix[bottom][i]);
            }
            bottom--;
        }

        if (left &lt;= right) {
            // Move up
            for (int i = bottom; i &gt;= top; i--) {
                result.push_back(matrix[i][left]);
            }
            left++;
        }
    }

    return result;
}

int main() {
    std::vector&lt;std::vector&lt;int&gt;&gt; matrix = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    std::vector&lt;int&gt; result = spiralOrder(matrix);
    for (int num : result) {
        std::cout &lt;&lt; num &lt;&lt; &quot; &quot;;
    }
    std::cout &lt;&lt; std::endl;

    return 0;
}
</code></pre>
<p>In this C++ solution:</p>
<ul>
<li>The function <code>spiralOrder</code> takes a reference to a 2D vector (<code>matrix</code>) and returns a vector with the elements in spiral order.</li>
<li>The variables <code>top</code>, <code>bottom</code>, <code>left</code>, and <code>right</code> define the current spiral layer&#39;s boundaries.</li>
<li>The spiral traversal includes moving right, down, left, and up, with each direction bounded by the current layer&#39;s limits.</li>
<li>The loop continues until all layers are traversed, reducing the spiral layer by layer.</li>
</ul>
<h2 id="solution-approach-rust">Solution Approach (rust)</h2>
<pre><code class="language-rust">fn spiral_order(matrix: Vec&lt;Vec&lt;i32&gt;&gt;) -&gt; Vec&lt;i32&gt; {
    if matrix.is_empty() {
        return Vec::new();
    }

    let mut result = Vec::new();
    let (mut top, mut bottom) = (0, matrix.len() - 1);
    let (mut left, mut right) = (0, matrix[0].len() - 1);

    while left &lt;= right &amp;&amp; top &lt;= bottom {
        // Move right
        for i in left..=right {
            result.push(matrix[top][i]);
        }
        top += 1;

        // Move down
        for i in top..=bottom {
            result.push(matrix[i][right]);
        }
        if right &gt; 0 {
            right -= 1;
        }

        // Move left
        if top &lt;= bottom {
            for i in (left..=right).rev() {
                result.push(matrix[bottom][i]);
            }
            bottom = bottom.saturating_sub(1);
        }

        // Move up
        if left &lt;= right {
            for i in (top..=bottom).rev() {
                result.push(matrix[i][left]);
            }
            left += 1;
        }
    }

    result
}

fn main() {
    let matrix = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];

    let result = spiral_order(matrix);
    println!(&quot;{:?}&quot;, result); // Output: [1, 2, 3, 6, 9, 8, 7, 4, 5]
}
</code></pre>
<p>In this Rust solution:</p>
<ul>
<li>The <code>spiral_order</code> function takes a matrix (a <code>Vec&lt;Vec&lt;i32&gt;&gt;</code>) and returns a vector containing the elements in spiral order.</li>
<li>The <code>top</code>, <code>bottom</code>, <code>left</code>, and <code>right</code> variables define the boundaries of the current spiral layer.</li>
<li>The code performs spiral traversal, moving right, down, left, and up within the boundaries of the current layer. It decreases the layer size after each direction.</li>
<li>The <code>saturating_sub</code> function is used to prevent underflow when decrementing <code>bottom</code>.</li>
<li>Rust&#39;s range syntax (<code>..=</code>) and its ability to reverse ranges (<code>rev()</code>) are used to iterate over rows and columns.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Spiral Matrix problem is a fascinating challenge that requires careful manipulation of array indices and boundaries. It is a popular question in technical interviews, testing understanding of 2D arrays and iterative traversals.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-spiral-matrix</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-spiral-matrix</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 12 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Word Search: Traversing a Letter Grid to Form Words]]></title>
            <description><![CDATA[<p>The &quot;Word Search&quot; problem involves searching for a specific word in a grid of letters, where the word can be formed by connecting letters horizontally or vertically.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a 2D board of letters and a word, check if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cells, where &quot;adjacent&quot; cells are those horizontally or vertically neighboring.</p>
<h2 id="example">Example</h2>
<p><img src="/assets/blind-75/79.word-search/word2.jpg" alt="Word Search Example"></p>
<ul>
<li><strong>Input</strong>:<br>Board:</li>
</ul>
<pre><code class="language-json">[
  [&#39;A&#39;,&#39;B&#39;,&#39;C&#39;,&#39;E&#39;],
  [&#39;S&#39;,&#39;F&#39;,&#39;C&#39;,&#39;S&#39;],
  [&#39;A&#39;,&#39;D&#39;,&#39;E&#39;,&#39;E&#39;]
]
</code></pre>
<p>Word: <code>&quot;ABCCED&quot;</code></p>
<ul>
<li><strong>Output</strong>: <code>true</code></li>
</ul>
<h2 id="solution-approach-typescript">Solution Approach (typescript)</h2>
<pre><code class="language-typescript">function exist(board: string[][], word: string): boolean {
  function dfs(board: string[][], i: number, j: number, count: number, word: string): boolean {
    if (count === word.length) return true;
    if (
      i &lt; 0 ||
      i &gt;= board.length ||
      j &lt; 0 ||
      j &gt;= board[i].length ||
      board[i][j] !== word[count]
    ) {
      return false;
    }

    let temp = board[i][j];
    board[i][j] = &#39; &#39;;
    let found =
      dfs(board, i + 1, j, count + 1, word) ||
      dfs(board, i - 1, j, count + 1, word) ||
      dfs(board, i, j + 1, count + 1, word) ||
      dfs(board, i, j - 1, count + 1, word);

    board[i][j] = temp;
    return found;
  }

  for (let i = 0; i &lt; board.length; i++) {
    for (let j = 0; j &lt; board[i].length; j++) {
      if (board[i][j] === word[0] &amp;&amp; dfs(board, i, j, 0, word)) {
        return true;
      }
    }
  }
  return false;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Depth-First Search (DFS)</strong>: Use DFS to traverse the board, exploring each possible path.</p>
</li>
<li><p><strong>Check Each Cell</strong>: Start from each cell that matches the first letter of the word, and recursively check its neighbors.</p>
</li>
<li><p><strong>Track Progress</strong>: Temporarily mark cells as visited during each DFS iteration to avoid revisiting them in the same path.</p>
</li>
<li><p><strong>Return Result</strong>: If the word is found, return <code>true</code>; if the board is fully explored without finding the word, return <code>false</code>.</p>
</li>
</ul>
<h2 id="solution-in-go">Solution in Go</h2>
<pre><code class="language-go">package main

import (
    &quot;fmt&quot;
)

func exist(board [][]byte, word string) bool {
    for i := 0; i &lt; len(board); i++ {
        for j := 0; j &lt; len(board[i]); j++ {
            if dfs(board, i, j, word, 0) {
                return true
            }
        }
    }
    return false
}

func dfs(board [][]byte, i, j int, word string, count int) bool {
    if count == len(word) {
        return true
    }
    if i &lt; 0 || i &gt;= len(board) || j &lt; 0 || j &gt;= len(board[0]) || board[i][j] != word[count] {
        return false
    }

    temp := board[i][j]
    board[i][j] = byte(&#39; &#39;)
    found := dfs(board, i+1, j, word, count+1) ||
        dfs(board, i-1, j, word, count+1) ||
        dfs(board, i, j+1, word, count+1) ||
        dfs(board, i, j-1, word, count+1)

    board[i][j] = temp
    return found
}

func main() {
    board := [][]byte{
        {&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;E&#39;},
        {&#39;S&#39;, &#39;F&#39;, &#39;C&#39;, &#39;S&#39;},
        {&#39;A&#39;, &#39;D&#39;, &#39;E&#39;, &#39;E&#39;},
    }
    word := &quot;ABCCED&quot;
    fmt.Println(exist(board, word)) // Output: true
}
</code></pre>
<p>In this Go implementation:</p>
<ul>
<li>The <code>exist</code> function checks if a given word exists in the board. It iterates over each cell in the board and calls the <code>dfs</code> (Depth-First Search) function.</li>
<li>The <code>dfs</code> function performs a depth-first search from the current cell to check if the remaining characters of the word can be formed. It marks the cell as visited by replacing the character with a space and then recursively checks adjacent cells.</li>
<li>If <code>dfs</code> returns <code>true</code> at any point, <code>exist</code> will return <code>true</code>, indicating the word is found in the board.</li>
<li>After the recursive call, the cell&#39;s original character is restored.</li>
</ul>
<h2 id="solution-in-c">Solution in C++</h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

bool dfs(vector&lt;vector&lt;char&gt;&gt;&amp; board, int i, int j, string&amp; word, int count) {
    if (count == word.length()) {
        return true;
    }
    if (i &lt; 0 || i &gt;= board.size() || j &lt; 0 || j &gt;= board[0].size() || board[i][j] != word[count]) {
        return false;
    }

    char temp = board[i][j];
    board[i][j] = &#39; &#39;;
    bool found = dfs(board, i + 1, j, word, count + 1) 
              || dfs(board, i - 1, j, word, count + 1) 
              || dfs(board, i, j + 1, word, count + 1) 
              || dfs(board, i, j - 1, word, count + 1);
    
    board[i][j] = temp;
    return found;
}

bool exist(vector&lt;vector&lt;char&gt;&gt;&amp; board, string word) {
    for (int i = 0; i &lt; board.size(); i++) {
        for (int j = 0; j &lt; board[i].size(); j++) {
            if (board[i][j] == word[0] &amp;&amp; dfs(board, i, j, word, 0)) {
                return true;
            }
        }
    }
    return false;
}

int main() {
    vector&lt;vector&lt;char&gt;&gt; board = {
        {&#39;A&#39;,&#39;B&#39;,&#39;C&#39;,&#39;E&#39;},
        {&#39;S&#39;,&#39;F&#39;,&#39;C&#39;,&#39;S&#39;},
        {&#39;A&#39;,&#39;D&#39;,&#39;E&#39;,&#39;E&#39;}
    };
    string word = &quot;ABCCED&quot;;

    cout &lt;&lt; (exist(board, word) ? &quot;true&quot; : &quot;false&quot;) &lt;&lt; endl;

    return 0;
}
</code></pre>
<p>In this C++ solution:</p>
<ul>
<li>The <code>dfs</code> function performs a depth-first search from the current cell, recursively checking adjacent cells to form the word. It temporarily marks the cell as visited by setting it to a space character and restores it after the recursive calls.</li>
<li>The <code>exist</code> function iterates over each cell in the board, starting a new DFS search whenever it finds the first character of the word.</li>
<li>If <code>dfs</code> returns <code>true</code> for any starting cell, the entire function returns <code>true</code>, indicating the word is found.</li>
<li>Compile and run this program to check if the given word exists in the board.</li>
</ul>
<h2 id="solution-in-python">Solution in Python</h2>
<pre><code class="language-python">def exist(board, word):
    def dfs(board, i, j, word, count):
        if count == len(word):
            return True
        if i &lt; 0 or i &gt;= len(board) or j &lt; 0 or j &gt;= len(board[0]) or board[i][j] != word[count]:
            return False

        temp = board[i][j]
        board[i][j] = &#39; &#39;  # Mark as visited
        found = dfs(board, i + 1, j, word, count + 1) or \
                dfs(board, i - 1, j, word, count + 1) or \
                dfs(board, i, j + 1, word, count + 1) or \
                dfs(board, i, j - 1, word, count + 1)
        
        board[i][j] = temp  # Reset the state
        return found

    for i in range(len(board)):
        for j in range(len(board[0])):
            if board[i][j] == word[0] and dfs(board, i, j, word, 0):
                return True
    return False

# Example usage
board = [
    [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;E&#39;],
    [&#39;S&#39;, &#39;F&#39;, &#39;C&#39;, &#39;S&#39;],
    [&#39;A&#39;, &#39;D&#39;, &#39;E&#39;, &#39;E&#39;]
]
word = &quot;ABCCED&quot;
print(exist(board, word))  # Output: True
</code></pre>
<p>In this Python solution:</p>
<ul>
<li>The <code>dfs</code> function is defined within <code>exist</code> to utilize the scope of <code>board</code> and <code>word</code>. It performs a depth-first search from the current cell.</li>
<li>The cell is temporarily marked as visited by setting it to a space character, and then restored to its original value after the recursive calls.</li>
<li><code>exist</code> iterates over the board, calling <code>dfs</code> for each cell that matches the first letter of the word.</li>
<li>If <code>dfs</code> returns <code>True</code>, the word exists in the board; otherwise, it does not.</li>
</ul>
<h2 id="solution-in-java">Solution in Java</h2>
<pre><code class="language-java">public class WordSearch {
    public boolean exist(char[][] board, String word) {
        for (int i = 0; i &lt; board.length; i++) {
            for (int j = 0; j &lt; board[i].length; j++) {
                if (board[i][j] == word.charAt(0) &amp;&amp; dfs(board, i, j, 0, word)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean dfs(char[][] board, int i, int j, int count, String word) {
        if (count == word.length()) return true;
        if (i &lt; 0 || i &gt;= board.length || j &lt; 0 || j &gt;= board[0].length || board[i][j] != word.charAt(count)) return false;

        char temp = board[i][j];
        board[i][j] = &#39; &#39;; // Mark as visited
        boolean found = dfs(board, i + 1, j, count + 1, word) 
                     || dfs(board, i - 1, j, count + 1, word)
                     || dfs(board, i, j + 1, count + 1, word)
                     || dfs(board, i, j - 1, count + 1, word);

        board[i][j] = temp; // Reset state
        return found;
    }

    public static void main(String[] args) {
        WordSearch solution = new WordSearch();
        char[][] board = {
            {&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;E&#39;},
            {&#39;S&#39;, &#39;F&#39;, &#39;C&#39;, &#39;S&#39;},
            {&#39;A&#39;, &#39;D&#39;, &#39;E&#39;, &#39;E&#39;}
        };
        String word = &quot;ABCCED&quot;;
        System.out.println(solution.exist(board, word)); // Output: true
    }
}
</code></pre>
<p>In this Java solution:</p>
<ul>
<li>The <code>exist</code> method iterates over each cell in the board, starting a DFS search from cells that match the first character of the word.</li>
<li>The <code>dfs</code> method performs a depth-first search to check if the word can be formed, starting from the current cell. It marks the cell as visited by setting it to a space character and resets it to its original value after exploring all possible paths from that cell.</li>
<li>If <code>dfs</code> returns <code>true</code> at any point, <code>exist</code> will return <code>true</code>, indicating that the word is found in the board.</li>
<li>The <code>main</code> method demonstrates how to use the <code>WordSearch</code> class with a sample board and word.</li>
</ul>
<h2 id="solution-in-kotlin">Solution in Kotlin</h2>
<pre><code class="language-kotlin">class WordSearch {
    fun exist(board: Array&lt;CharArray&gt;, word: String): Boolean {
        for (i in board.indices) {
            for (j in board[0].indices) {
                if (board[i][j] == word[0] &amp;&amp; dfs(board, i, j, 0, word)) {
                    return true
                }
            }
        }
        return false
    }

    private fun dfs(board: Array&lt;CharArray&gt;, i: Int, j: Int, count: Int, word: String): Boolean {
        if (count == word.length) return true
        if (i &lt; 0 || i &gt;= board.size || j &lt; 0 || j &gt;= board[0].size || board[i][j] != word[count]) return false

        val temp = board[i][j]
        board[i][j] = &#39; &#39;  // Mark as visited
        val found = dfs(board, i + 1, j, count + 1, word)
                  || dfs(board, i - 1, j, count + 1, word)
                  || dfs(board, i, j + 1, count + 1, word)
                  || dfs(board, i, j - 1, count + 1, word)

        board[i][j] = temp  // Reset state
        return found
    }
}

fun main() {
    val solution = WordSearch()
    val board = arrayOf(
        charArrayOf(&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;E&#39;),
        charArrayOf(&#39;S&#39;, &#39;F&#39;, &#39;C&#39;, &#39;S&#39;),
        charArrayOf(&#39;A&#39;, &#39;D&#39;, &#39;E&#39;, &#39;E&#39;)
    )
    val word = &quot;ABCCED&quot;
    println(solution.exist(board, word)) // Output: true
}
</code></pre>
<p>In this Kotlin solution:</p>
<ul>
<li>The <code>exist</code> function iterates over each cell in the board, starting a DFS search from cells that match the first character of the word.</li>
<li>The <code>dfs</code> function performs a depth-first search to check if the word can be formed, starting from the current cell. It marks the cell as visited by setting it to a space character and resets it to its original value after the recursive calls.</li>
<li>If <code>dfs</code> returns <code>true</code> for any starting cell, <code>exist</code> will return <code>true</code>, indicating the word is found in the board.</li>
<li>The <code>main</code> function demonstrates how to use the <code>WordSearch</code> class with a sample board and word.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Word Search problem is a classic example of using DFS in a matrix-like structure. It tests one&#39;s ability to implement recursive search algorithms and handle edge cases in grid traversal.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-word-search</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-word-search</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 12 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Insert Interval: Merging Intervals in Arrays]]></title>
            <description><![CDATA[<p>The &quot;Insert Interval&quot; problem is a common algorithmic challenge, involving the insertion and merging of intervals in a sorted list.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a list of non-overlapping intervals sorted by their start times, insert a new interval into the list so that the list remains sorted and any overlapping intervals are merged.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Intervals <code>[[1,3],[6,9]]</code>, New Interval <code>[2,5]</code><br><strong>Output</strong>: <code>[[1,5],[6,9]]</code><br><strong>Explanation</strong>: The new interval <code>[2,5]</code> overlaps with <code>[1,3]</code> and should be merged into <code>[1,5]</code>.</li>
</ul>
<h2 id="solution-approach">Solution Approach</h2>
<pre><code class="language-javascript">function insert(intervals, newInterval) {
    let result = [];
    let i = 0;

    // Add all intervals ending before newInterval starts
    while (i &lt; intervals.length &amp;&amp; intervals[i][1] &lt; newInterval[0]) {
        result.push(intervals[i]);
        i++;
    }

    // Merge all overlapping intervals to one considering newInterval
    while (i &lt; intervals.length &amp;&amp; intervals[i][0] &lt;= newInterval[1]) {
        newInterval = [
            Math.min(newInterval[0], intervals[i][0]),
            Math.max(newInterval[1], intervals[i][1])
        ];
        i++;
    }
    result.push(newInterval); // Add the merged interval

    // Add all the rest
    while (i &lt; intervals.length) {
        result.push(intervals[i]);
        i++;
    }

    return result;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initial Non-Overlapping Intervals</strong>: Add all intervals that end before the new interval starts to the result.</p>
</li>
<li><p><strong>Merging Overlapping Intervals</strong>: Iterate through all intervals that overlap with the new interval and merge them into a single interval.</p>
</li>
<li><p><strong>Add Remaining Intervals</strong>: Finally, add the remaining intervals that start after the new interval ends.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Insert Interval problem is an excellent example of interval manipulation and requires a careful approach to handle overlapping and merging. It is a common scenario in calendar and scheduling applications, making it a practical problem in software development.</p>
<h2 id="binary-search-solution">Binary Search Solution</h2>
<pre><code class="language-javascript">function insert(intervals, newInterval) {
    let left = 0, right = intervals.length - 1;
    while (left &lt;= right) {
        let mid = Math.floor((left + right) / 2);
        if (intervals[mid][1] &lt; newInterval[0]) {
            left = mid + 1;
        } else if (intervals[mid][0] &gt; newInterval[1]) {
            right = mid - 1;
        } else {
            newInterval = [
                Math.min(newInterval[0], intervals[mid][0]),
                Math.max(newInterval[1], intervals[mid][1])
            ];
            intervals.splice(mid, 1);
            left = mid; // Adjust left to recheck the same mid index
        }
    }

    intervals.splice(left, 0, newInterval); // Insert the new/merged interval

    // Merge overlapping intervals if necessary
    let i = left;
    while (i &lt; intervals.length - 1) {
        if (intervals[i][1] &gt;= intervals[i + 1][0]) {
            intervals[i] = [
                intervals[i][0],
                Math.max(intervals[i][1], intervals[i + 1][1])
            ];
            intervals.splice(i + 1, 1);
        } else {
            i++;
        }
    }

    return intervals;
}
</code></pre>
<h2 id="breaking-down-the-solution-1">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Binary Search for Insertion Point</strong>: Use binary search to find the correct position or overlapping interval for the new interval.</p>
</li>
<li><p><strong>Insert and Merge</strong>: Insert the new interval at the found position. Then, iterate through the list to merge any overlapping intervals resulting from the insertion.</p>
</li>
<li><p><strong>Optimized Overlapping Check</strong>: Post-insertion, check only nearby intervals for any potential overlap, reducing the number of comparisons.</p>
</li>
</ul>
<h2 id="conclusion-1">Conclusion</h2>
<hr>
<p>Using binary search in the Insert Interval problem significantly enhances the efficiency of finding the correct position for insertion, especially in cases with a large number of intervals. This approach exemplifies the power of combining binary search with interval merging for optimized solutions in array manipulation tasks.</p>
<h2 id="divide-and-conquer-solution">Divide and Conquer solution</h2>
<pre><code class="language-typescript">export function insertIntervalDivideAndConquer(
  intervals: [number, number][],
  newInterval: [number, number]
): [number, number][] {
  // Base case: if the intervals list is empty
  if (intervals.length === 0) {
    return [newInterval];
  }

  // Base case: if the intervals list contains only one interval
  if (intervals.length === 1) {
    return mergeIntervals(intervals[0], newInterval);
  }

  // Divide the intervals list into two halves
  const mid = Math.floor(intervals.length / 2);
  const leftPart = insertIntervalDivideAndConquer(intervals.slice(0, mid), newInterval);
  const rightPart = insertIntervalDivideAndConquer(intervals.slice(mid), newInterval);

  // Conquer: merge the two halves back together
  return mergeSortedIntervals(leftPart, rightPart);
}

// Helper function to merge two intervals if they overlap
function mergeIntervals(
  interval1: [number, number],
  interval2: [number, number]
): [number, number][] {
  if (interval1[1] &lt; interval2[0] || interval2[1] &lt; interval1[0]) {
    return [interval1, interval2].sort((a, b) =&gt; a[0] - b[0]);
  } else {
    return [[Math.min(interval1[0], interval2[0]), Math.max(interval1[1], interval2[1])]];
  }
}

// Helper function to merge two sorted lists of intervals
function mergeSortedIntervals(
  part1: [number, number][],
  part2: [number, number][]
): [number, number][] {
  let result = [],
    i = 0,
    j = 0;

  while (i &lt; part1.length &amp;&amp; j &lt; part2.length) {
    let interval1 = part1[i],
      interval2 = part2[j];
    if (interval1[1] &lt; interval2[0]) {
      result.push(interval1);
      i++;
    } else if (interval2[1] &lt; interval1[0]) {
      result.push(interval2);
      j++;
    } else {
      const merged = mergeIntervals(interval1, interval2);
      result.push(...merged);
      i++;
      j++;
    }
  }

  while (i &lt; part1.length) result.push(part1[i++]);
  while (j &lt; part2.length) result.push(part2[j++]);

  return result;
}
</code></pre>
<p>In this solution:</p>
<ol>
<li>The list of intervals is recursively split into two halves.</li>
<li>The <code>mergeIntervals</code> helper function is used to merge intervals if they overlap.</li>
<li>The <code>mergeSortedIntervals</code> function merges the two halves back together, ensuring that the result remains sorted and that all intervals are properly merged.</li>
</ol>
<p>This approach is more complex than iterative solutions but showcases an alternative way of thinking about the problem.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-insert-interval</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-insert-interval</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Merge Intervals: Simplifying Overlapping Ranges]]></title>
            <description><![CDATA[<p>The &quot;Merge Intervals&quot; problem is a fundamental challenge in array manipulation, involving the combination of overlapping intervals into a minimal set of non-overlapping intervals.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of intervals where each interval is represented as a pair <code>[start, end]</code>, merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Intervals <code>[[1,3],[2,6],[8,10],[15,18]]</code><br><strong>Output</strong>: <code>[[1,6],[8,10],[15,18]]</code><br><strong>Explanation</strong>: Since intervals <code>[1,3]</code> and <code>[2,6]</code> overlap, they are merged into <code>[1,6]</code>.</li>
</ul>
<h2 id="solution-approach">Solution Approach</h2>
<pre><code class="language-javascript">function merge(intervals) {
    if (!intervals.length) return [];

    // Sort the intervals based on the start times
    intervals.sort((a, b) =&gt; a[0] - b[0]);

    const merged = [intervals[0]];

    for (let i = 1; i &lt; intervals.length; i++) {
        const lastMerged = merged[merged.length - 1];
        const current = intervals[i];

        if (current[0] &lt;= lastMerged[1]) {
            // Overlapping intervals, merge them
            lastMerged[1] = Math.max(lastMerged[1], current[1]);
        } else {
            // Non-overlapping interval, add to the result
            merged.push(current);
        }
    }

    return merged;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Sort Intervals</strong>: First, sort the intervals based on their starting points.</p>
</li>
<li><p><strong>Initialize Merged List</strong>: Start with the first interval in the merged list.</p>
</li>
<li><p><strong>Iterate and Merge</strong>: Go through each interval and merge it with the last interval in the merged list if they overlap. If they don&#39;t overlap, add the interval to the merged list.</p>
</li>
<li><p><strong>Return Merged Intervals</strong>: The merged list now contains the minimal set of non-overlapping intervals.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Merge Intervals problem is a classic example of interval manipulation and is critical in many applications, such as calendar events, scheduling algorithms, and time-based data analysis. It emphasizes the importance of sorting and efficient merging in array processing.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-merge-intervals</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-merge-intervals</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Merge Two Sorted Lists: Combining Linked Lists in Order]]></title>
            <description><![CDATA[<p>The &quot;Merge Two Sorted Lists&quot; problem is a fundamental exercise in linked list manipulation, focusing on merging two sorted lists into one.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Merge two sorted linked lists and return it as a new sorted list. The new list should be made by splicing together the nodes of the first two lists.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: List1 <code>1 -&gt; 2 -&gt; 4</code>, List2 <code>1 -&gt; 3 -&gt; 4</code></li>
<li><strong>Output</strong>: Merged List <code>1 -&gt; 1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 4</code></li>
</ul>
<h2 id="iterative-solution">Iterative Solution</h2>
<pre><code class="language-javascript">class ListNode {
    val: number;
    next: ListNode | null;

    constructor(val?: number, next?: ListNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.next = (next === undefined ? null : next);
    }
}

function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode | null {
    let dummyHead = new ListNode(0);
    let current = dummyHead;

    while (l1 !== null &amp;&amp; l2 !== null) {
        if (l1.val &lt; l2.val) {
            current.next = l1;
            l1 = l1.next;
        } else {
            current.next = l2;
            l2 = l2.next;
        }
        current = current.next;
    }

    // Attach the remaining part of l1 or l2
    current.next = l1 ? l1 : l2;

    return dummyHead.next;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialize a Dummy Head</strong>: Start with a dummy head to simplify edge cases and maintain a reference to the head of the merged list.</p>
</li>
<li><p><strong>Iterate Through Both Lists</strong>: Compare nodes from both lists, appending the smaller node to the merged list.</p>
</li>
<li><p><strong>Handle Remaining Nodes</strong>: Once one of the lists is exhausted, attach the remaining part of the other list to the merged list.</p>
</li>
<li><p><strong>Return Merged List</strong>: The <code>next</code> of the dummy head points to the start of the merged list.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Merging two sorted linked lists is a common problem that demonstrates the importance of pointer manipulation in data structures. It&#39;s a key skill for many algorithms and applications involving linked lists.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-merge-two-sorted-lists</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-merge-two-sorted-lists</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Non-overlapping Intervals: Optimizing Interval Arrangement]]></title>
            <description><![CDATA[<p>The &quot;Non-overlapping Intervals&quot; problem is a key challenge in interval manipulation, focusing on minimizing overlaps in a set of intervals.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Intervals <code>[[1,2],[2,3],[3,4],[1,3]]</code><br><strong>Output</strong>: <code>1</code><br><strong>Explanation</strong>: Removing the interval <code>[1,3]</code> leaves <code>[1,2]</code>, <code>[2,3]</code>, and <code>[3,4]</code>, which are non-overlapping.</li>
</ul>
<h2 id="greedy-solution-approach">Greedy Solution Approach</h2>
<pre><code class="language-javascript">function eraseOverlapIntervals(intervals) {
    if (!intervals.length) return 0;

    // Sort intervals based on their end times
    intervals.sort((a, b) =&gt; a[1] - b[1]);

    let end = intervals[0][1];
    let count = 0;

    for (let i = 1; i &lt; intervals.length; i++) {
        if (intervals[i][0] &lt; end) {
            // Overlapping interval, increment count
            count++;
        } else {
            // Update end time for the next comparison
            end = intervals[i][1];
        }
    }

    return count;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Sort by End Time</strong>: Sort the intervals by their end times to ensure a minimal number of removals.</p>
</li>
<li><p><strong>Count Removals</strong>: Iterate through the intervals, counting each time an interval overlaps with the previous one.</p>
</li>
<li><p><strong>Update End Time</strong>: After a non-overlapping interval is found, update the end time for the next comparison.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Non-overlapping Intervals problem is an excellent application of greedy algorithms in optimizing interval arrangements. It highlights the importance of strategic sorting and interval selection in minimizing removals and is a common scenario in resource allocation and scheduling systems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-non-overlapping-intervals</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-non-overlapping-intervals</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Remove Nth Node From End of List: Manipulating Linked Lists]]></title>
            <description><![CDATA[<p>The &quot;Remove Nth Node From End of List&quot; problem is a common challenge in linked list manipulation, focusing on removing a node from a specific position counting from the end of the list.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the head of a linked list, remove the nth node from the end of the list and return its head.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Linked List <code>1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5</code>, <code>n = 2</code></li>
<li><strong>Output</strong>: Modified List <code>1 -&gt; 2 -&gt; 3 -&gt; 5</code></li>
</ul>
<h2 id="solution-approach---two-pointer-technique">Solution Approach - Two Pointer Technique</h2>
<pre><code class="language-javascript">class ListNode {
    val: number;
    next: ListNode | null;

    constructor(val?: number, next?: ListNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.next = (next === undefined ? null : next);
    }
}

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
    let dummy = new ListNode(0);
    dummy.next = head;
    let first: ListNode | null = dummy;
    let second: ListNode | null = dummy;

    // Advance first pointer by n+1 steps
    for (let i = 0; i &lt;= n; i++) {
        if (first) {
            first = first.next;
        }
    }

    // Move first to the end, maintaining the gap
    while (first !== null) {
        first = first.next;
        if (second) {
            second = second.next;
        }
    }

    // Skip the desired node
    if (second &amp;&amp; second.next) {
        second.next = second.next.next;
    }

    return dummy.next;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize Two Pointers</strong>: Use two pointers, <code>first</code> and <code>second</code>, both starting from a dummy node before the head.</p>
</li>
<li><p><strong>Advance the First Pointer</strong>: Move <code>first</code> n+1 steps ahead, creating a gap of n nodes between <code>first</code> and <code>second</code>.</p>
</li>
<li><p><strong>Move Both Pointers</strong>: Traverse the list with both pointers until <code>first</code> reaches the end. At this point, <code>second</code> is just before the nth node from the end.</p>
</li>
<li><p><strong>Remove the Nth Node</strong>: Adjust the <code>next</code> pointer of the <code>second</code> node to skip the nth node.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Remove Nth Node From End of List problem is an excellent exercise in pointer manipulation and demonstrates the two-pointer technique&#39;s usefulness in linked list problems. It highlights a common scenario in data structure manipulation and algorithm design.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-remove-nth-node-from-end</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-remove-nth-node-from-end</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reorder List: Rearranging Nodes in a Linked List]]></title>
            <description><![CDATA[<p>The &quot;Reorder List&quot; problem is a unique challenge in linked list manipulation, involving the reordering of nodes in a specific pattern.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a singly linked list, reorder it such that the list follows the pattern: first node, last node, second node, second last node, and so on.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: Linked List <code>1 -&gt; 2 -&gt; 3 -&gt; 4</code></li>
<li><strong>Output</strong>: Reordered List <code>1 -&gt; 4 -&gt; 2 -&gt; 3</code></li>
</ul>
<h2 id="solution-approach">Solution Approach</h2>
<pre><code class="language-typescript">class ListNode {
    val: number;
    next: ListNode | null;

    constructor(val?: number, next?: ListNode | null) {
        this.val = (val === undefined ? 0 : val);
        this.next = (next === undefined ? null : next);
    }
}

function reorderList(head: ListNode | null): void {
    if (!head || !head.next) return;

    // Step 1: Find the middle of the list
    let slow: ListNode | null = head, fast: ListNode | null = head;
    while (fast &amp;&amp; fast.next) {
        slow = slow!.next;
        fast = fast.next.next;
    }

    // Step 2: Reverse the second half of the list
    let prev: ListNode | null = null;
    let curr: ListNode | null = slow;
    let temp: ListNode | null;
    while (curr) {
        temp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = temp;
    }

    // Step 3: Merge the two halves
    let first: ListNode | null = head, second: ListNode | null = prev;
    while (second &amp;&amp; second.next) {
        temp = first!.next;
        first!.next = second;
        first = temp;

        temp = second.next;
        second.next = first;
        second = temp;
    }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Find Middle</strong>: Use the fast and slow pointer technique to find the middle of the list.</p>
</li>
<li><p><strong>Reverse Second Half</strong>: Reverse the second half of the list starting from the middle.</p>
</li>
<li><p><strong>Merge Halves</strong>: Alternately merge nodes from the first half and the reversed second half.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Reorder List problem is an excellent exercise in linked list operations, combining techniques like finding the middle of a list, reversing a list, and merging lists. It showcases complex manipulation of data structures and is a useful skill for many algorithmic challenges.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-reorder-list</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-reorder-list</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reverse Linked List: Inverting Node Connections]]></title>
            <description><![CDATA[<p>The &quot;Reverse Linked List&quot; problem is a classic algorithmic challenge, involving the reversal of a singly linked list.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the head of a singly linked list, reverse the list and return the reversed list.</p>
<h2 id="example">Example</h2>
<p>Consider a linked list: <code>1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5</code><br>After reversing, the list becomes: <code>5 -&gt; 4 -&gt; 3 -&gt; 2 -&gt; 1</code></p>
<h2 id="iterative-solution">Iterative Solution</h2>
<pre><code class="language-javascript">function reverseList(head) {
    let prev = null;
    let current = head;

    while (current !== null) {
        let nextTemp = current.next;
        current.next = prev;
        prev = current;
        current = nextTemp;
    }

    return prev; // New head of the reversed list
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize Pointers</strong>: Start with <code>prev</code> set to <code>null</code> and <code>current</code> set to the head of the list.</p>
</li>
<li><p><strong>Iterate Through List</strong>: Traverse the list, reversing the pointers at each node.</p>
</li>
<li><p><strong>Update Pointers</strong>: For each node, point it to the <code>prev</code> node, then update <code>prev</code> to be the current node and move <code>current</code> to the next node in the original list.</p>
</li>
<li><p><strong>Return New Head</strong>: At the end of the iteration, <code>prev</code> will be the new head of the reversed list.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Reverse Linked List problem is a fundamental exercise in linked list manipulation, demonstrating the importance of pointer manipulation in data structures. It is a valuable skill for understanding more complex linked list operations and problems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-reverse-linked-list</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-reverse-linked-list</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 06 Jan 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Number of Islands: Exploring Grid-Based Graph Algorithms]]></title>
            <description><![CDATA[<p>The &quot;Number of Islands&quot; problem is a classic algorithmic challenge that involves counting the number of distinct islands in a 2D grid.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a 2D grid map of <code>&#39;1&#39;</code>s (land) and <code>&#39;0&#39;</code>s (water), determine the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically.</p>
<h2 id="example">Example</h2>
<p>Consider a grid map:<br>11110<br>11010<br>11000<br>00000</p>
<p>The number of islands in this grid is 1.</p>
<h2 id="depth-first-search-solution">Depth-First Search Solution</h2>
<pre><code class="language-javascript">function numIslands(grid) {
    if (!grid || !grid.length) return 0;

    let numIslands = 0;

    function dfs(row, col) {
        if (row &lt; 0 || row &gt;= grid.length || col &lt; 0 || col &gt;= grid[0].length || grid[row][col] === &#39;0&#39;) {
            return;
        }
        grid[row][col] = &#39;0&#39;; // Mark as visited
        dfs(row + 1, col); // Down
        dfs(row - 1, col); // Up
        dfs(row, col + 1); // Right
        dfs(row, col - 1); // Left
    }

    for (let i = 0; i &lt; grid.length; i++) {
        for (let j = 0; j &lt; grid[i].length; j++) {
            if (grid[i][j] === &#39;1&#39;) {
                numIslands++;
                dfs(i, j);
            }
        }
    }

    return numIslands;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>DFS Traversal</strong>: Use depth-first search to explore each land cell and mark it as visited by setting it to <code>&#39;0&#39;</code>.</p>
</li>
<li><p><strong>Count Islands</strong>: Iterate over each cell in the grid. When a land cell (<code>&#39;1&#39;</code>) is found, increment the island count and use DFS to mark the entire island.</p>
</li>
<li><p><strong>Handle Edge Cases</strong>: Check for invalid indices and water cells (<code>&#39;0&#39;</code>) in the DFS function to prevent out-of-bounds errors and unnecessary exploration.</p>
</li>
</ul>
<h3 id="time-complexity">Time Complexity</h3>
<p>The time complexity is <strong>O(M x N)</strong>, where <code>M</code> is the number of rows and <code>N</code> is the number of columns in the grid. This is because, in the worst case, the algorithm needs to visit every cell in the grid once. The DFS traversal ensures that each cell is visited only once, so the total number of operations is proportional to the total number of cells.</p>
<h3 id="space-complexity">Space Complexity</h3>
<p>The space complexity is also <strong>O(M x N)</strong> in the worst case. This is due to the recursive nature of DFS, which could potentially have a call stack with a depth equal to the number of cells in the grid in the worst case (e.g., a grid that is entirely land).</p>
<h3 id="can-it-be-improved">Can It Be Improved?</h3>
<ul>
<li><strong>Space Complexity</strong>: One way to improve the space complexity is to use an iterative DFS approach with an explicit stack instead of recursion. This can help in scenarios where the grid is large, and recursion might lead to a stack overflow.</li>
<li><strong>Alternative Approach - BFS</strong>: Another way to traverse the grid is by using breadth-first search (BFS). While BFS does not improve the worst-case time complexity, it can be more practical in terms of space complexity, especially if the grid forms one large island, as BFS will keep the queue size minimal relative to the size of the island being explored.</li>
<li><strong>Union-Find (Disjoint Set)</strong>: An alternative approach is to use the Union-Find algorithm. This can be particularly efficient if there are many queries on the grid after some modifications (e.g., adding or removing land). However, the implementation complexity is higher compared to DFS or BFS.</li>
</ul>
<p>In practice, the choice of algorithm might depend on the specific characteristics of the input data and the constraints of the problem (e.g., grid size, number of islands, likelihood of stack overflow, etc.).    </p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Number of Islands problem is an essential application of depth-first search in a grid-based context. It highlights how grid traversal can be used to solve complex problems in areas such as mapping, geographical information systems, and computer graphics.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-number-of-islands</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-number-of-islands</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sun, 31 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Course Schedule: Navigating Dependencies with Graph Theory]]></title>
            <description><![CDATA[<p>The &quot;Course Schedule&quot; problem is a fundamental challenge in graph theory and topological sorting, commonly encountered in computer science.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given the total number of courses numbered from <code>0</code> to <code>n - 1</code> and a list of prerequisite pairs, determine if it&#39;s possible for a student to finish all courses. A prerequisite pair <code>[a, b]</code> indicates that course <code>a</code> must be taken before course <code>b</code>.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>numCourses = 2</code>, <code>prerequisites = [[1, 0]]</code><br><strong>Output</strong>: <code>true</code><br><strong>Explanation</strong>: There are a total of 2 courses to take. To take course 1, you must first take course 0. So it is possible.</p>
</li>
<li><p><strong>Input</strong>: <code>numCourses = 2</code>, <code>prerequisites = [[1, 0], [0, 1]]</code><br><strong>Output</strong>: <code>false</code><br><strong>Explanation</strong>: There are a total of 2 courses to take. To take course 1, you must first take course 0, and to take course 0, you must first take course 1. Thus, it is impossible to finish all courses.</p>
</li>
</ul>
<h2 id="graph-theory-and-topological-sorting">Graph theory and topological sorting</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Graph_theory" target="_blank" rel="noopener noreferrer">Graph theory</a> is a branch of mathematics that studies the properties of graphs, which are mathematical structures used to model pairwise relations between objects. A graph in this context is made up of vertices (also called nodes or points) and edges (also called links or lines) that connect them.</li>
<li><a href="/documents/03Graphs.pdf" target="_blank" rel="noopener noreferrer">Graphs</a> document for reading and understanding graphs.</li>
</ul>
<h2 id="graph-theory-solution">Graph Theory Solution</h2>
<pre><code class="language-javascript">function canFinish(numCourses, prerequisites) {
    const graph = new Array(numCourses).fill(0).map(() =&gt; []);
    const indegree = new Array(numCourses).fill(0);

    for (let [crs, pre] of prerequisites) {
        graph[pre].push(crs);
        indegree[crs]++;
    }

    const queue = [];
    for (let i = 0; i &lt; numCourses; i++) {
        if (indegree[i] === 0) queue.push(i);
    }

    while (queue.length) {
        const curr = queue.shift();
        numCourses--;
        for (let next of graph[curr]) {
            if (--indegree[next] === 0) queue.push(next);
        }
    }

    return numCourses === 0;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><strong>Create Graph and Indegree Array</strong>: Build a graph to represent prerequisites and an array to track the number of prerequisites (indegree) for each course.</li>
</ul>
<p>&quot;Indegree&quot; in the context of graph theory refers to the number of edges coming into a vertex (or node) in a directed graph. In simpler terms, it&#39;s the count of how many arrows are pointing to a node in a graph.</p>
<p>Let&#39;s break this down with an example, especially in the context of a problem like the Course Schedule:</p>
<p>Imagine each course is a point or a node in a graph, and a prerequisite is an arrow that points from one course to another. For instance, if Course A is a prerequisite for Course B, there would be an arrow pointing from A to B.</p>
<p>In this scenario:</p>
<ul>
<li>The <strong>indegree</strong> of Course B is the number of prerequisites it has. So if Course B has two prerequisites, Course A and Course C, its indegree is 2 (because there are two arrows pointing to it).</li>
<li>A course with an indegree of 0 means it has no prerequisites and can be taken immediately.<br>Understanding indegree helps determine the order in which courses should be taken and is crucial in solving problems that involve scheduling and dependency resolution, like the Course Schedule problem.</li>
</ul>
<ul>
<li><p><strong>Queue for Courses with No Prerequisites</strong>: Initialize a queue with courses that don&#39;t have any prerequisites.</p>
</li>
<li><p><strong>Process Courses</strong>: Remove courses from the queue one by one and decrease the indegree of their dependent courses. If a dependent course&#39;s indegree becomes 0, add it to the queue.</p>
</li>
<li><p><strong>Check Course Completion</strong>: If all courses are processed (numCourses reaches 0), then it is possible to finish all courses.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Course Schedule problem demonstrates the practical application of graph theory and topological sorting in real-world scenarios, such as planning and scheduling. It emphasizes the importance of understanding dependencies and order in complex systems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-course-schedule</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-course-schedule</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 30 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Pacific Atlantic Water Flow: Exploring Water Movement in a Matrix]]></title>
            <description><![CDATA[<p>The &quot;Pacific Atlantic Water Flow&quot; problem is a unique challenge that combines elements of graph theory and depth-first search (DFS) in a matrix setting.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an <code>m x n</code> matrix of non-negative integers representing the height of each unit cell in a continent, determine the list of grid coordinates where water can flow to both the Pacific and Atlantic oceans. Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.</p>
<h2 id="example">Example</h2>
<p>Consider a matrix:<br>Pacific ~ ~ ~ ~ ~<br>~ 1 2 2 3 (5) *<br>~ 3 2 3 (4) (4) *<br>~ 2 4 (5) 3 1 *<br>~ (6) (7) 1 4 5 *<br>~ (5) 1 1 2 4 *</p>
<ul>
<li><ul>
<li><ul>
<li><ul>
<li>Atlantic</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The cells marked with <code>*</code> are the ones where water can flow to both oceans.</p>
<h2 id="depth-first-search-solution">Depth-First Search Solution</h2>
<pre><code class="language-javascript">function pacificAtlantic(heights) {
    if (!heights || !heights.length) return [];
    
    const m = heights.length, n = heights[0].length;
    const pacific = Array.from({ length: m }, () =&gt; new Array(n).fill(false));
    const atlantic = Array.from({ length: m }, () =&gt; new Array(n).fill(false));

    function dfs(row, col, ocean) {
        if (ocean[row][col]) return;
        ocean[row][col] = true;

        [[-1, 0], [1, 0], [0, -1], [0, 1]].forEach(([dr, dc]) =&gt; {
            const newRow = row + dr, newCol = col + dc;
            if (newRow &gt;= 0 &amp;&amp; newRow &lt; m &amp;&amp; newCol &gt;= 0 &amp;&amp; newCol &lt; n &amp;&amp; heights[newRow][newCol] &gt;= heights[row][col]) {
                dfs(newRow, newCol, ocean);
            }
        });
    }

    for (let i = 0; i &lt; m; i++) {
        dfs(i, 0, pacific);
        dfs(i, n - 1, atlantic);
    }
    for (let i = 0; i &lt; n; i++) {
        dfs(0, i, pacific);
        dfs(m - 1, i, atlantic);
    }

    const result = [];
    for (let i = 0; i &lt; m; i++) {
        for (let j = 0; j &lt; n; j++) {
            if (pacific[i][j] &amp;&amp; atlantic[i][j]) {
                result.push([i, j]);
            }
        }
    }
    return result;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize Oceans</strong>: Create two matrices, <code>pacific</code> and <code>atlantic</code>, to track the cells reachable from each ocean.</p>
</li>
<li><p><strong>Depth-First Search</strong>: Perform DFS from the edges of the matrix towards the interior. Mark cells reachable from each ocean in their respective matrices.</p>
</li>
<li><p><strong>Collect Results</strong>: Iterate over the entire matrix, and for each cell reachable from both oceans, add its coordinates to the result list.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Pacific Atlantic Water Flow problem showcases the application of DFS in matrix traversal and is an excellent example of how to handle complex flow and reachability problems in a grid. It emphasizes depth-first search&#39;s versatility in exploring paths and conditions in a matrix.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-pacific-atlantic-water-flow</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-pacific-atlantic-water-flow</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 30 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Clone Graph: A Deep Copy Challenge]]></title>
            <description><![CDATA[<p>The &quot;Clone Graph&quot; problem is a classic challenge in computer science, focusing on the creation of a deep copy of a graph.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a reference to a node in a connected undirected graph, return a deep copy (clone) of the graph. Each node in the graph contains a value (<code>val</code>) and a list (<code>neighbors</code>) of its neighbors.</p>
<h2 id="example">Example</h2>
<p>Consider a graph with nodes labeled 1, 2, 3, and 4, connected in the following structure:</p>
<ul>
<li>Node 1 is connected to nodes 2 and 4.</li>
<li>Node 2 is connected to nodes 1 and 3.</li>
<li>Node 3 is connected to nodes 2 and 4.</li>
<li>Node 4 is connected to nodes 1 and 3.</li>
</ul>
<p>A deep copy of this graph would be a new graph with the same structure but with different node instances.</p>
<h2 id="depth-first-search-solution">Depth-First Search Solution</h2>
<pre><code class="language-typescript">function cloneGraph(node: GraphNode) {
  if (!node) return null;
  const map = new Map();

  function dfs(node: GraphNode) {
    if (map.has(node)) return map.get(node);

    const clone = new GraphNode(node.val);
    map.set(node, clone);

    for (let neighbor of node.neighbors) {
      clone.neighbors.push(dfs(neighbor));
    }
    return clone;
  }

  return dfs(node);
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Handle Empty Graph</strong>: Return <code>null</code> if the input graph is empty.</p>
</li>
<li><p><strong>Map for Cloned Nodes</strong>: Use a map to track cloned nodes to avoid duplications and handle cycles in the graph.</p>
</li>
<li><p><strong>Depth-First Search (DFS)</strong>: Implement a DFS function to traverse the graph. For each node, create a clone and recursively clone its neighbors.</p>
</li>
<li><p><strong>Return Cloned Graph</strong>: Start DFS from the given node and return the cloned graph.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Clone Graph problem exemplifies the application of depth-first search in graph theory and the intricacies of creating deep copies of complex structures. It&#39;s a valuable exercise for understanding graph traversal and the nuances of object references in programming.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-clone-graph</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-clone-graph</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Combination Sum IV: A Dynamic Programming Solution]]></title>
            <description><![CDATA[<p>The &quot;Combination Sum IV&quot; problem is a dynamic programming challenge that focuses on finding the total number of possible combinations that add up to a given target number, using elements from an array.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of distinct integers <code>nums</code> and a target integer <code>target</code>, return the number of possible combinations that add up to <code>target</code>.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>nums = [1, 2, 3]</code>, <code>target = 4</code><br><strong>Output</strong>: <code>7</code><br><strong>Explanation</strong>: The possible combination ways are:<ul>
<li>(1, 1, 1, 1)</li>
<li>(1, 1, 2)</li>
<li>(1, 2, 1)</li>
<li>(1, 3)</li>
<li>(2, 1, 1)</li>
<li>(2, 2)</li>
<li>(3, 1)</li>
</ul>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function combinationSum4(nums, target) {
    let dp = new Array(target + 1).fill(0);
    dp[0] = 1;

    for (let i = 1; i &lt;= target; i++) {
        for (let num of nums) {
            if (i &gt;= num) {
                dp[i] += dp[i - num];
            }
        }
    }

    return dp[target];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize dp Array</strong>: Create a dp array of length target + 1 and initialize it with zeros. Set dp[0] to 1, representing the base case.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>: Iterate through each possible sum from 1 to target. For each sum, iterate through the numbers in nums and add to dp[i] the number of ways to reach i - num.</p>
</li>
<li><p><strong>Calculate Total Combinations</strong>: By the end of the iterations, dp[target] contains the total number of ways to reach the target sum using numbers from nums.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Combination Sum IV problem is a valuable exercise in dynamic programming, demonstrating how to efficiently solve problems related to counting and combinations. It illustrates the importance of building up solutions for smaller subproblems and combining them to form the solution to the overall problem.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-combination-sum-iv</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-combination-sum-iv</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Decode Ways: Unraveling Encoded Messages with Dynamic Programming]]></title>
            <description><![CDATA[<p>The &quot;Decode Ways&quot; problem is a dynamic programming challenge that revolves around decoding a string of digits into alphabets, akin to the way messages were encoded in the past.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a string <code>s</code> containing only digits, return the number of ways to decode it into letters using the mapping: &#39;1&#39; -&gt; &#39;A&#39;, &#39;2&#39; -&gt; &#39;B&#39;, ..., &#39;26&#39; -&gt; &#39;Z&#39;.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>s = &quot;12&quot;</code><br><strong>Output</strong>: <code>2</code><br><strong>Explanation</strong>: It could be decoded as &quot;AB&quot; (1 2) or &quot;L&quot; (12).</p>
</li>
<li><p><strong>Input</strong>: <code>s = &quot;226&quot;</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: It could be decoded as &quot;BZ&quot; (2 26), &quot;VF&quot; (22 6), or &quot;BBF&quot; (2 2 6).</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function numDecodings(s) {
    if (s[0] === &#39;0&#39;) return 0;
    let dp = new Array(s.length + 1).fill(0);
    dp[0] = 1;
    dp[1] = 1;

    for (let i = 2; i &lt;= s.length; i++) {
        let oneDigit = parseInt(s.slice(i - 1, i));
        let twoDigits = parseInt(s.slice(i - 2, i));

        if (oneDigit &gt;= 1) {
            dp[i] += dp[i - 1];
        }
        if (twoDigits &gt;= 10 &amp;&amp; twoDigits &lt;= 26) {
            dp[i] += dp[i - 2];
        }
    }

    return dp[s.length];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Handle Leading Zero</strong>: If the string starts with &#39;0&#39;, return 0, as it can&#39;t be decoded.</p>
</li>
<li><p><strong>Initialize <code>dp</code> Array</strong>: Create a <code>dp</code> array to store the number of ways to decode up to each character in the string.</p>
</li>
<li><p><strong>Iterate and Update <code>dp</code></strong>: For each character, check if it forms a valid one-digit or two-digit number and update <code>dp</code> accordingly.</p>
</li>
<li><p><strong>Return Decoding Count</strong>: The last element in the <code>dp</code> array gives the total number of ways to decode the entire string.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Decode Ways problem is an interesting application of dynamic programming in string processing. It showcases how to approach problems where solutions depend on the number of ways previous subproblems have been solved, illustrating the flexibility and utility of dynamic programming in a wide range of scenarios.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-decode-ways</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-decode-ways</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[House Robber II: Dynamic Programming with a Twist]]></title>
            <description><![CDATA[<p>The &quot;House Robber II&quot; problem is an extension of the classic House Robber problem, with an added complexity: the houses are arranged in a circle.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a list of non-negative integers representing the amount of money in each house, find the maximum amount of money you can rob tonight without alerting the police. In this version, the first and last houses are adjacent; if you rob one, you cannot rob the other.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>nums = [2, 3, 2]</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: Rob the second house (3) because robbing the first and the last house is not allowed due to their adjacency.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [1, 2, 3, 1]</code><br><strong>Output</strong>: <code>4</code><br><strong>Explanation</strong>: Rob the first house (1) and the third house (3), totaling 4.</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function rob(nums) {
    if (nums.length === 0) return 0;
    if (nums.length === 1) return nums[0];
    
    function robLinear(houses) {
        let prev = 0, curr = 0;
        for (let amount of houses) {
            let temp = curr;
            curr = Math.max(prev + amount, curr);
            prev = temp;
        }
        return curr;
    }

    return Math.max(
        robLinear(nums.slice(1)),
        robLinear(nums.slice(0, -1))
    );
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Base Cases</strong>: Handle scenarios with no houses or only one house.</p>
</li>
<li><p><strong>Rob Houses Linearly</strong>: Define a function <code>robLinear</code> that solves the problem for a linear arrangement of houses, using a dynamic programming approach.</p>
</li>
<li><p><strong>Two Scenarios</strong>: Since the houses are in a circle, consider two scenarios - one excluding the first house and the other excluding the last house.</p>
</li>
<li><p><strong>Maximize the Robbery</strong>: Use the <code>robLinear</code> function for both scenarios and return the maximum of the two.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>House Robber II introduces an interesting twist to the standard dynamic programming problem by arranging the houses in a circle. This problem requires careful consideration of edge cases and illustrates the adaptability of dynamic programming techniques in solving complex variations of standard problems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-house-robber-ii</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-house-robber-ii</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[House Robber: A Dynamic Programming Solution]]></title>
            <description><![CDATA[<p>The &quot;House Robber&quot; problem is a fundamental question in dynamic programming. It challenges us to find the maximum amount of money a robber can steal from a row of houses without robbing two adjacent houses, as this would alert the police.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of integers representing the amount of money in each house, determine the maximum amount of money you can rob without robbing two adjacent houses.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>nums = [1, 2, 3, 1]</code><br><strong>Output</strong>: <code>4</code><br><strong>Explanation</strong>: Rob the first house (1) and the third house (3), totaling 4.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [2, 7, 9, 3, 1]</code><br><strong>Output</strong>: <code>12</code><br><strong>Explanation</strong>: Rob the first house (2), the third house (9), and the fifth house (1), totaling 12.</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function rob(nums) {
    if (nums.length === 0) return 0;
    if (nums.length === 1) return nums[0];

    let dp = [nums[0], Math.max(nums[0], nums[1])];

    for (let i = 2; i &lt; nums.length; i++) {
        dp[i] = Math.max(nums[i] + dp[i - 2], dp[i - 1]);
    }

    return dp[nums.length - 1];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Base Cases</strong>: Handle the cases where there are no houses or only one house.</p>
</li>
<li><p><strong>Initialize <code>dp</code> Array</strong>: Create a <code>dp</code> array to store the maximum amount of money that can be robbed up to each house.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>: Iterate through the array. For each house, calculate the maximum money by either robbing this house and the best house before the previous one, or by not robbing this house and taking the best total from the previous house.</p>
</li>
<li><p><strong>Return the Maximum Robbery Amount</strong>: The last element in the <code>dp</code> array represents the maximum amount of money that can be robbed.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The House Robber problem demonstrates the effectiveness of dynamic programming in solving optimization problems. It shows how to make decisions at each step to maximize the overall outcome while adhering to certain constraints.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-house-robber</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-house-robber</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Jump Game: Mastering Dynamic Programming for Pathfinding]]></title>
            <description><![CDATA[<p>The &quot;Jump Game&quot; problem is a compelling dynamic programming challenge that tests one&#39;s ability to determine if it&#39;s possible to reach the end of an array from the start by jumping between elements.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array of non-negative integers <code>nums</code>, where each element represents the maximum number of steps that can be jumped forward from that position, determine if it&#39;s possible to reach the last index starting from the first index.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>nums = [2, 3, 1, 1, 4]</code><br><strong>Output</strong>: <code>true</code><br><strong>Explanation</strong>: Jump 1 step from index 0 to 1, then 3 steps to the last index.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [3, 2, 1, 0, 4]</code><br><strong>Output</strong>: <code>false</code><br><strong>Explanation</strong>: You will always arrive at index 3 no matter what. It&#39;s impossible to jump to the last index from there.</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function canJump(nums) {
    let goal = nums.length - 1;

    for (let i = nums.length - 2; i &gt;= 0; i--) {
        if (i + nums[i] &gt;= goal) {
            goal = i;
        }
    }

    return goal === 0;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Set the Goal</strong>: Initialize the <code>goal</code> variable to the last index of the array.</p>
</li>
<li><p><strong>Backward Iteration</strong>: Iterate through the array backward. For each position, check if it&#39;s possible to reach the <code>goal</code> from that position.</p>
</li>
<li><p><strong>Update the Goal</strong>: If a position can reach the <code>goal</code>, update the <code>goal</code> to be this new position.</p>
</li>
<li><p><strong>Check Reachability</strong>: If the start of the array (<code>index 0</code>) becomes the new <code>goal</code>, it means the end is reachable. Return <code>true</code> if the <code>goal</code> is 0, indicating reachability.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Jump Game problem is a fascinating exercise in dynamic programming and pathfinding within arrays. It emphasizes the importance of strategy in solving complex problems and showcases how dynamic programming can be applied in various situations, including games and simulations.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-jump-game</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-jump-game</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Common Subsequence: A Dynamic Programming Solution]]></title>
            <description><![CDATA[<p>The &quot;Longest Common Subsequence&quot; (LCS) problem is a well-known challenge in computer science. It involves finding the longest sequence of characters that appear in the same order in both of two given strings.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two strings <code>text1</code> and <code>text2</code>, find the length of their longest common subsequence. A subsequence is a sequence that appears in the same relative order in both strings but isn&#39;t necessarily contiguous.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><p><strong>Input</strong>: <code>text1 = &quot;abcde&quot;</code>, <code>text2 = &quot;ace&quot;</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: The longest common subsequence is &quot;ace&quot; and its length is 3.</p>
</li>
<li><p><strong>Input</strong>: <code>text1 = &quot;abc&quot;</code>, <code>text2 = &quot;abc&quot;</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: The longest common subsequence is &quot;abc&quot; and its length is 3.</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function longestCommonSubsequence(text1, text2) {
    let m = text1.length, n = text2.length;
    let dp = Array.from({length: m + 1}, () =&gt; new Array(n + 1).fill(0));

    for (let i = 1; i &lt;= m; i++) {
        for (let j = 1; j &lt;= n; j++) {
            if (text1[i - 1] === text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[m][n];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialization</strong>: Create a 2D array <code>dp</code> with dimensions <code>(len(text1) + 1) x (len(text2) + 1)</code> and initialize all elements to 0.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>: Iterate over each character in <code>text1</code> and <code>text2</code>. Update <code>dp[i][j]</code> with the length of the LCS up to that point.</p>
</li>
<li><p><strong>Character Match</strong>: If characters match (<code>text1[i - 1] === text2[j - 1]</code>), increment the length of the LCS by 1 from the previous characters&#39; LCS length.</p>
</li>
<li><p><strong>Character Mismatch</strong>: If characters don&#39;t match, carry forward the maximum LCS length found so far.</p>
</li>
<li><p><strong>Return the LCS Length</strong>: The value in <code>dp[m][n]</code> gives the length of the LCS.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The LCS problem is a fundamental dynamic programming challenge, demonstrating how to break down a complex problem into smaller sub-problems. It&#39;s widely used in text comparison, DNA sequencing, and understanding the principles of building up solutions incrementally.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-common-subsequence</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-common-subsequence</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Unique Paths: A Dynamic Programming Approach]]></title>
            <description><![CDATA[<p>The &quot;Unique Paths&quot; problem is a fundamental dynamic programming challenge that involves finding the number of distinct paths from the top-left corner to the bottom-right corner in a grid.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a <code>m x n</code> grid, find the number of unique paths that the robot can take to reach the bottom-right corner from the top-left corner. The robot can only move either down or right at any point in time.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>m = 3</code>, <code>n = 2</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:<ol>
<li>Right -&gt; Right -&gt; Down</li>
<li>Right -&gt; Down -&gt; Right</li>
<li>Down -&gt; Right -&gt; Right</li>
</ol>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function uniquePaths(m, n) {
    const dp = Array.from(Array(m), () =&gt; new Array(n).fill(1));

    for (let i = 1; i &lt; m; i++) {
        for (let j = 1; j &lt; n; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }

    return dp[m - 1][n - 1];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize <code>dp</code> Array</strong>: Create a <code>m x n</code> <code>dp</code> array and initialize all elements to 1. Each cell represents the number of paths to reach that cell.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>: Iterate through the grid, and for each cell, calculate the number of paths by adding the paths from the top and left cells.</p>
</li>
<li><p><strong>Return Total Unique Paths</strong>: The value in <code>dp[m - 1][n - 1]</code> gives the total number of unique paths to reach the bottom-right corner.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Unique Paths problem is an excellent example of dynamic programming applied to grid-based problems. It demonstrates how to incrementally build up solutions and is essential for understanding pathfinding and navigation within grids in various applications.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-unique-paths</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-unique-paths</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Word Break Problem: A Dynamic Programming Approach]]></title>
            <description><![CDATA[<p>The &quot;Word Break&quot; problem is a popular question in dynamic programming. It involves determining whether a given string can be segmented into a sequence of one or more dictionary words.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a non-empty string <code>s</code> and a dictionary <code>wordDict</code> containing a list of non-empty words, determine if <code>s</code> can be segmented into a space-separated sequence of one or more dictionary words.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: <code>s = &quot;leetcode&quot;</code>, <code>wordDict = [&quot;leet&quot;, &quot;code&quot;]</code><br><strong>Output</strong>: <code>true</code><br><strong>Explanation</strong>: The string &quot;leetcode&quot; can be segmented as &quot;leet code&quot;.</p>
</li>
<li><p><strong>Input</strong>: <code>s = &quot;applepenapple&quot;</code>, <code>wordDict = [&quot;apple&quot;, &quot;pen&quot;]</code><br><strong>Output</strong>: <code>true</code><br><strong>Explanation</strong>: The string can be segmented as &quot;apple pen apple&quot;.</p>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-javascript">function wordBreak(s, wordDict) {
    let wordSet = new Set(wordDict);
    let dp = new Array(s.length + 1).fill(false);
    dp[0] = true;

    for (let i = 1; i &lt;= s.length; i++) {
        for (let j = 0; j &lt; i; j++) {
            if (dp[j] &amp;&amp; wordSet.has(s.substring(j, i))) {
                dp[i] = true;
                break;
            }
        }
    }

    return dp[s.length];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Initialize <code>dp</code> Array</strong>: Create an array <code>dp</code> of length <code>s.length + 1</code> and initialize all elements to <code>false</code>, except <code>dp[0]</code>, which is <code>true</code>.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>: Iterate through the string <code>s</code>. For each position <code>i</code>, check all substrings ending at <code>i</code>. If any substring is found in <code>wordDict</code> and the remaining part of the string up to the start of the substring is also breakable (as indicated by <code>dp</code>), mark <code>dp[i]</code> as <code>true</code>.</p>
</li>
<li><p><strong>Check for Word Break</strong>: Return the value of <code>dp[s.length]</code>. If it&#39;s <code>true</code>, it means the string <code>s</code> can be segmented into words from the dictionary.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Word Break problem is an excellent application of dynamic programming to solve string manipulation challenges. It shows how problems can be solved by breaking them down into smaller, more manageable subproblems, and then combining these solutions to solve the larger problem.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-word-break</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-word-break</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 29 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Increasing Subsequence: A Dynamic Programming Challenge]]></title>
            <description><![CDATA[<p>The &quot;Longest Increasing Subsequence&quot; (LIS) problem is a classic example in the realm of dynamic programming. It involves identifying the length of the longest subsequence in a given array where the elements are in strictly increasing order.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an integer array <code>nums</code>, the task is to find the length of the longest strictly increasing subsequence.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><p><strong>Input</strong>: <code>nums = [10,9,2,5,3,7,101,18]</code><br><strong>Output</strong>: <code>4</code><br><strong>Explanation</strong>: The longest increasing subsequence is <code>[2,3,7,101]</code>.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [0,1,0,3,2,3]</code><br><strong>Output</strong>: <code>4</code><br><strong>Explanation</strong>: One example of the longest increasing subsequence is <code>[0,1,2,3]</code>.</p>
</li>
</ul>
<h2 id="javascript-solution-dynamic-programming">JavaScript Solution (Dynamic Programming)</h2>
<pre><code class="language-javascript">function lengthOfLIS(nums) {
    if (nums.length === 0) return 0;
    let dp = new Array(nums.length).fill(1);
    let maxAns = 1;

    for (let i = 1; i &lt; nums.length; i++) {
        for (let j = 0; j &lt; i; j++) {
            if (nums[i] &gt; nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        maxAns = Math.max(maxAns, dp[i]);
    }
    return maxAns;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialize <code>dp</code> Array</strong>:<br>A dynamic programming (<code>dp</code>) array is created and initially filled with 1s. This is because the minimum length of the Longest Increasing Subsequence (LIS) for each element is 1, considering each element as a subsequence by itself.</p>
</li>
<li><p><strong>Iterate and Update <code>dp</code></strong>:<br>For each element in the array <code>nums</code>, the algorithm iterates and compares it with all previous elements. If <code>nums[i]</code> is greater than a previous element <code>nums[j]</code>, the algorithm updates <code>dp[i]</code>. It sets <code>dp[i]</code> to be the maximum of its current value and <code>dp[j] + 1</code>. This update reflects the addition of the current element to the increasing subsequence ending at <code>nums[j]</code>.</p>
</li>
<li><p><strong>Track the Maximum Length</strong>:<br>Throughout the iterations, the algorithm continually updates the maximum length of the LIS found so far. This is done by maintaining the maximum value in the <code>dp</code> array.</p>
</li>
<li><p><strong>Return the LIS Length</strong>:<br>The final result, which is the length of the longest increasing subsequence, is obtained from the maximum value in the <code>dp</code> array. This value represents the overall LIS in the entire array.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>The Longest Increasing Subsequence problem is a key challenge in dynamic programming. It demonstrates the power and efficiency of this technique in solving complex computational problems. This problem is exemplary in illustrating the concepts of subsequences and showcases how dynamic programming can be used to build up solutions incrementally and efficiently, making it a staple in algorithmic problem-solving.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-increasing-subsequence</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-increasing-subsequence</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Wed, 27 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Climbing Stairs: A Dynamic Programming Approach]]></title>
            <description><![CDATA[<p>The &quot;Climbing Stairs&quot; problem is a classic example used to illustrate dynamic programming in algorithmic problem-solving. It involves finding the number of distinct ways to climb a staircase with a given number of steps.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a staircase with <code>n</code> steps, where each time you can either climb 1 or 2 steps, the task is to determine the total number of distinct ways to reach the top of the staircase.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><p><strong>Input</strong>: <code>n = 2</code><br><strong>Output</strong>: <code>2</code><br><strong>Explanation</strong>: There are two ways to climb to the top:</p>
<ol>
<li>1 step + 1 step</li>
<li>2 steps</li>
</ol>
</li>
<li><p><strong>Input</strong>: <code>n = 3</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: There are three ways to climb to the top:</p>
<ol>
<li>1 step + 1 step + 1 step</li>
<li>1 step + 2 steps</li>
<li>2 steps + 1 step</li>
</ol>
</li>
</ul>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<p>Here&#39;s how you can solve this problem using dynamic programming in JavaScript:</p>
<pre><code class="language-javascript">function climbStairs(n) {
    if (n === 1) return 1;
    let dp = [1, 2];
    for (let i = 2; i &lt; n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n - 1];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Base Cases</strong>:<br>If <code>n</code> is 1, the answer is straightforwardly 1. The dynamic programming array <code>dp</code> is initialized with its base cases: <code>dp[0] = 1</code> and <code>dp[1] = 2</code>. These represent the number of ways to climb a staircase with one step and two steps, respectively.</p>
</li>
<li><p><strong>Filling the <code>dp</code> Array</strong>:<br>For each step from 2 to <code>n - 1</code>, the function calculates the number of ways to reach that step. The value of <code>dp[i]</code> is determined as the sum of <code>dp[i - 1]</code> and <code>dp[i - 2]</code>. This represents the total ways to climb to the current step, either by taking one step from the previous step or two steps from the step before that.</p>
</li>
<li><p><strong>Returning the Result</strong>:<br>The final result is stored in <code>dp[n - 1]</code>, which gives the total number of distinct ways to reach the top of the staircase. This value is returned as the solution to the problem.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>The &quot;Climbing Stairs&quot; problem is a classic example that showcases the efficacy of dynamic programming in solving computational problems related to combinations and counting. It emphasizes the importance of breaking down the problem into smaller, overlapping subproblems and building up the solution by storing and reusing intermediate results. This approach not only makes the solution more efficient but also simplifies the process of solving complex problems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-climbing-stairs</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-climbing-stairs</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Tue, 26 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Coin Change Problem: A Dynamic Programming Approach]]></title>
            <description><![CDATA[<p>The &quot;Coin Change&quot; problem is a notable problem in the field of dynamic programming. It involves finding the minimum number of coins needed to make a specific amount of money, given an array of coin denominations.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array <code>coins</code> representing different coin denominations and an integer <code>amount</code>, the goal is to find the fewest number of coins needed to make up the given amount. If it&#39;s not possible to make up the amount with the given coins, return -1.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><p><strong>Input</strong>: <code>coins = [1, 2, 5]</code>, <code>amount = 11</code><br><strong>Output</strong>: <code>3</code><br><strong>Explanation</strong>: The amount 11 can be composed by 5 + 5 + 1, hence 3 coins.</p>
</li>
<li><p><strong>Input</strong>: <code>coins = [2]</code>, <code>amount = 3</code><br><strong>Output</strong>: <code>-1</code></p>
</li>
</ul>
<h2 id="javascript-solution">JavaScript Solution</h2>
<pre><code class="language-javascript">function coinChange(coins, amount) {
    const max = amount + 1;
    const dp = new Array(max).fill(max);
    dp[0] = 0;

    for (let i = 1; i &lt;= amount; i++) {
        for (let j = 0; j &lt; coins.length; j++) {
            if (coins[j] &lt;= i) {
                dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
            }
        }
    }

    return dp[amount] &gt; amount ? -1 : dp[amount];
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialize <code>dp</code> Array</strong>:<br>Create an array <code>dp</code> of size <code>amount + 1</code>, initializing all elements to <code>amount + 1</code>, except for <code>dp[0]</code>, which is set to 0. This initialization prepares the array to store the minimum number of coins required for each amount up to the given <code>amount</code>.</p>
</li>
<li><p><strong>Dynamic Programming Iteration</strong>:<br>Iterate through each amount from 1 to <code>amount</code>. In each iteration, also iterate through the available coin denominations. The goal is to find the minimum number of coins needed for each specific amount.</p>
</li>
<li><p><strong>Updating the <code>dp</code> Array</strong>:<br>For each coin denomination that is less than or equal to the current amount being considered, update <code>dp[i]</code>. Set it to the minimum of its current value and the value calculated for <code>i - coins[j]</code> (the current amount minus the coin denomination) plus one. This step involves comparing and selecting the best option among the previously computed values.</p>
</li>
<li><p><strong>Return Result</strong>:<br>After completing the iterations, check the value of <code>dp[amount]</code>. If it is greater than <code>amount</code>, it implies that it&#39;s not possible to make up the amount with the given coins, and the function should return -1. If it&#39;s not greater than <code>amount</code>, return <code>dp[amount]</code>, which represents the minimum number of coins needed.</p>
</li>
</ul>
<h2 id="lets-explain-the-coin-change-problem-in-a-way-thats-easy-for-a-10-year-old-to-understand">Let&#39;s explain the &quot;Coin Change&quot; problem in a way that&#39;s easy for a 10-year-old to understand.</h2>
<p>Imagine you have a piggy bank full of coins of different values - like 1 cent, 5 cents, or 10 cents - and you want to buy a toy that costs a certain amount of money, say 11 cents. Now, the challenge is to find the smallest number of coins you can use to make exactly 11 cents.</p>
<p>It&#39;s like a puzzle! You try different combinations of coins to see which one gives you 11 cents using the least number of coins.</p>
<p><strong>Here’s how you might solve it:</strong></p>
<p><strong>Start With No Coins:</strong> Think of starting with no coins and then adding one coin at a time to see how many ways you can reach the total amount you need.</p>
<p><strong>Add Coins One by One:</strong></p>
<p>First, see if you can make 1 cent, then 2 cents, and so on, all the way up to 11 cents.<br>For each amount, check all the different coins you could use. For example, to make 4 cents, you could use four 1-cent coins or two 2-cent coins.<br>Keep Track of the Best Way:</p>
<p>For each amount, you keep track of the smallest number of coins needed.<br>You write down the best way to make each amount, like a cheat sheet. So, when you want to make 6 cents, you look back at your cheat sheet to see the best ways to make smaller amounts like 5 cents, 4 cents, etc., and then add one more coin.<br>Find the Smallest Number of Coins for Your Toy:</p>
<p>Once you reach the amount that the toy costs, look at your cheat sheet.<br>The number you wrote down for the toy&#39;s cost is the smallest number of coins you can use to buy it.<br>Think of it like a game where you try to score exactly 11 points, and each coin is worth different points. You want to score exactly, and you want to use the fewest turns (or coins) possible to win!</p>
<p>This is what computers do in the &quot;Coin Change&quot; problem – they try all combinations in a smart way to find the answer using the fewest coins.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The &quot;Coin Change&quot; problem effectively demonstrates the power of dynamic programming in solving problems involving the search for optimal combinations. By incrementally building up the solution for increasing amounts and efficiently utilizing previously computed results, this approach provides an elegant and efficient solution to the problem, emphasizing the importance of identifying and optimizing overlapping subproblems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-coin-change</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-coin-change</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Tue, 26 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Counting Bits: A Bit Manipulation Challenge]]></title>
            <description><![CDATA[<p>The &quot;Counting Bits&quot; problem is a classic bit manipulation challenge, often encountered in coding interviews. It requires counting the number of 1s (set bits) in the binary representation of each number from 0 up to a given integer.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a non-negative integer <code>num</code>, the objective is to return an array <code>count</code> such that <code>count[i]</code> represents the number of 1s in the binary representation of <code>i</code>, for all <code>0 &lt;= i &lt;= num</code>.</p>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<p>Here&#39;s a JavaScript function that employs dynamic programming to solve this problem:</p>
<pre><code class="language-javascript">function countBits(num) {
    const count = new Array(num + 1).fill(0);
    
    for (let i = 1; i &lt;= num; i++) {
        count[i] = count[Math.floor(i / 2)] + (i % 2);
    }

    return count;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialize Array</strong>:<br>An array <code>count</code> of size <code>num + 1</code> is initialized with zeros. This array is crucial for storing the number of set bits (1s) for each number from 0 to <code>num</code>.</p>
</li>
<li><p><strong>Iterative Computation</strong>:<br>A loop is executed, iterating through numbers from 1 to <code>num</code>. In each iteration, the number of set bits for the current number <code>i</code> is calculated. This is done by leveraging the results computed in previous iterations.</p>
</li>
<li><p><strong>Using Previous Results</strong>:<br>The expression <code>count[Math.floor(i / 2)] + (i % 2)</code> effectively calculates the number of set bits in <code>i</code>. The idea is that the number of set bits in <code>i</code> is equal to the number of set bits in <code>i / 2</code> (which is the same number right-shifted by one bit) plus an additional bit if <code>i</code> is odd. The extra bit comes from the fact that odd numbers have their least significant bit set to 1.</p>
</li>
<li><p><strong>Return the Result</strong>:<br>After completing the iterations, the array <code>count</code> contains the number of set bits for each number in the range from 0 to <code>num</code>. This array is then returned as the final result.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>The &quot;Counting Bits&quot; problem showcases the elegance of dynamic programming when applied to bit manipulation. It demonstrates how complex problems can be simplified into smaller subproblems. By iteratively building up the solution and utilizing previously computed results, the algorithm efficiently counts set bits across a range of numbers, highlighting the synergistic power of dynamic programming and bitwise operations in algorithmic problem-solving.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-counting-bits</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-counting-bits</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Mon, 25 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Finding the Missing Number in a Sequence]]></title>
            <description><![CDATA[<p>The &quot;Missing Number&quot; problem is a classic example of array and bit manipulation in computer science. It involves finding a missing number in a sequence.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array containing <code>n</code> distinct numbers taken from <code>0</code> to <code>n</code>, find the one number that is missing from the sequence.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><p><strong>Input</strong>: <code>nums = [3,0,1]</code><br><strong>Output</strong>: <code>2</code><br><strong>Explanation</strong>: Numbers 0, 1, and 3 are present. The missing number is 2.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [0,1]</code><br><strong>Output</strong>: <code>2</code><br><strong>Explanation</strong>: Numbers 0 and 1 are present. The missing number is 2.</p>
</li>
</ul>
<h2 id="solutions">Solutions</h2>
<p><strong>Mathematical Solution</strong>:</p>
<pre><code class="language-javascript">function missingNumber(nums) {
    let expectedSum = nums.length * (nums.length + 1) / 2;
    let actualSum = nums.reduce((a, b) =&gt; a + b, 0);
    return expectedSum - actualSum;
}
</code></pre>
<p><strong>Bit Manipulation Solution</strong>:</p>
<pre><code class="language-javascript">function missingNumber(nums) {
    let xor = 0;
    for (let i = 0; i &lt; nums.length; i++) {
        xor ^= i ^ nums[i];
    }
    return xor ^ nums.length;
}
</code></pre>
<h2 id="breaking-down-the-solutions">Breaking Down the Solutions</h2>
<ul>
<li>Mathematical Approach:<ul>
<li>The sum of the first <code>n</code> numbers is <code>n * (n + 1) / 2</code>. We can use this formula to find the expected sum of the numbers in the array.</li>
<li>We can then find the actual sum of the numbers in the array by using the <code>reduce</code> method.</li>
<li>The difference between the expected sum and the actual sum is the missing number.</li>
</ul>
</li>
<li>Bit Manipulation Approach:<ul>
<li>We can use the XOR operator to find the missing number.</li>
<li>The XOR operator is a bitwise operator that returns a 1 if the bits are different and a 0 if the bits are the same.</li>
<li>We can use the XOR operator to find the missing number by XORing the index of each number in the array with the number itself.</li>
<li>The XOR operator is associative and commutative, so we can XOR the numbers in any order.</li>
<li>We can XOR the index of each number in the array with the number itself to find the missing number.</li>
</ul>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>The &quot;Missing Number&quot; problem is a classic example of array and bit manipulation in computer science. It involves finding a missing number in a sequence. We can solve this problem using mathematical and bit manipulation techniques.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-missing-number</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-missing-number</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Mon, 25 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reversing Bits of an Integer]]></title>
            <description><![CDATA[<p>The &quot;Reverse Bits&quot; problem is a classic bit manipulation challenge that involves reversing the bits of a given 32-bit unsigned integer.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a 32-bit unsigned integer <code>n</code>, the goal is to reverse its bits and return the result.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>n = 43261596</code> (binary representation: <code>00000010100101000001111010011100</code>)</li>
<li><strong>Output</strong>: <code>964176192</code> (binary representation: <code>00111001011110000010100101000000</code>)</li>
</ul>
<h2 id="javascript-solution">JavaScript Solution</h2>
<p>Here&#39;s an efficient way to solve this problem in JavaScript:</p>
<pre><code class="language-javascript">function reverseBits(n) {
    let result = 0;
    for (let i = 0; i &lt; 32; i++) {
        result = (result &lt;&lt; 1) | (n &amp; 1);
        n &gt;&gt;&gt;= 1;
    }
    return result &gt;&gt;&gt; 0; // Ensure unsigned 32-bit integer
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialization</strong>:<br>Start with <code>result</code> set to 0. This variable will hold the reversed bits.</p>
</li>
<li><p><strong>Iterative Bitwise Operations</strong>: For 32 iterations (each iteration represents a bit in the 32-bit integer):</p>
<ul>
<li><p><strong>Left-shift <code>result</code></strong>:<br>Shift <code>result</code> left by one bit (<code>result &lt;&lt; 1</code>). This operation makes space for adding the new bit at the least significant position.</p>
</li>
<li><p><strong>Add Bit to <code>result</code></strong>:<br>Use bitwise OR (<code>|</code>) to add the rightmost bit of <code>n</code> to <code>result</code>. The expression <code>n &amp; 1</code> isolates the least significant bit of <code>n</code>, which is then added to <code>result</code>.</p>
</li>
<li><p><strong>Right-shift <code>n</code></strong>:<br>Shift <code>n</code> right by one bit (<code>n &gt;&gt;&gt;= 1</code>). This operation moves all bits of <code>n</code> to the right by one position, bringing the next bit in line to be processed.</p>
</li>
</ul>
</li>
<li><p><strong>Return Unsigned Integer</strong>:<br>The expression <code>result &gt;&gt;&gt; 0</code> converts <code>result</code> to an unsigned 32-bit integer. This step ensures that the final returned value is in the correct format, respecting the constraints of the problem.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Reversing the bits of an integer is a valuable exercise in bit manipulation. It demonstrates how bitwise operations can be used to precisely control and manipulate individual bits within integers. This problem is not only frequently asked in technical interviews but also plays a crucial role in areas like low-level computing and digital signal processing, where bit-level manipulation is common.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-reverse-bits</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-reverse-bits</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Mon, 25 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Number of 1 Bits (Hamming Weight)]]></title>
            <description><![CDATA[<p>The &quot;Number of 1 Bits&quot; problem, also referred to as the Hamming weight calculation, is a common question in computer science that focuses on counting the number of 1 bits (set bits) in the binary representation of a number.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a non-negative integer <code>n</code>, count and return the number of &#39;1&#39; bits (also known as set bits) in its binary representation.</p>
<h2 id="javascript-solution">JavaScript Solution</h2>
<p>Here&#39;s a simple JavaScript function to solve this problem:</p>
<pre><code class="language-javascript">function hammingWeight(n) {
    let count = 0;
    while (n !== 0) {
        count += n &amp; 1;
        n &gt;&gt;&gt;= 1;
    }
    return count;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Initialize a Count Variable</strong>: let count = 0; initializes a variable to keep track of the number of 1 bits.</p>
</li>
<li><p><strong>Loop Until n is Zero</strong>: The loop while (n !== 0) {} continues until all bits of n have been checked.</p>
</li>
<li><p><strong>Count 1 Bits</strong>: count += n &amp; 1; adds 1 to count if the least significant bit of n is 1.</p>
</li>
<li><p><strong>Right Shift n</strong>: n &gt;&gt;&gt;= 1; performs a logical right shift on n, moving all bits to the right by one place. This step is crucial for checking the next bit in the next iteration.</p>
</li>
<li><p><strong>Return the Count</strong>: After all bits have been checked, the function returns the count of 1 bits.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Calculating the Hamming weight of a number is a fundamental operation in bit manipulation. This problem not only tests basic understanding of bitwise operations but also serves as a foundation for more complex bit manipulation challenges.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-number-of-1-bits</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-number-of-1-bits</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 23 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sum of Two Integers Without Using Plus or Minus]]></title>
            <description><![CDATA[<p>The &quot;Sum of Two Integers&quot; problem is a fascinating exercise in bit manipulation, where the objective is to calculate the sum of two integers without using the <code>+</code> or <code>-</code> operators.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given two integers <code>a</code> and <code>b</code>, the challenge is to compute their sum using only bitwise operators and without the conventional arithmetic operators.</p>
<h2 id="javascript-solution">JavaScript Solution</h2>
<p>Here&#39;s a JavaScript function that demonstrates the solution:</p>
<pre><code class="language-javascript">function getSum(a, b) {
    while (b !== 0) {
        let carry = (a &amp; b) &lt;&lt; 1;
        a = a ^ b;
        b = carry;
    }
    return a;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Carry Calculation</strong>:<br>Using <code>let carry = (a &amp; b) &lt;&lt; 1</code>, the carry from each bit is computed. The bitwise AND (<code>&amp;</code>) identifies the bits that are 1 in both <code>a</code> and <code>b</code>. The left shift (<code>&lt;&lt; 1</code>) then moves these bits to a higher order, representing the carry effect in binary addition.</p>
</li>
<li><p><strong>Sum Without Carry</strong>:<br>The expression <code>a = a ^ b</code> calculates the sum of <code>a</code> and <code>b</code> without considering the carry. The XOR operation (<code>^</code>) effectively adds the bits where there is at least one 1, aligning with how addition works in binary.</p>
</li>
<li><p><strong>Iterative Process</strong>:<br>A <code>while</code> loop continues this process of updating <code>a</code> with the sum and <code>b</code> with the new carry. This loop iterates until there is no carry left, indicated by <code>b</code> becoming 0.</p>
</li>
<li><p><strong>Result</strong>:<br>Once <code>b</code> is 0, it signifies that no further carry is being generated, and <code>a</code> contains the final computed sum. This sum is then returned as the solution.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>This problem elegantly demonstrates how bit manipulation can effectively replicate basic arithmetic operations, such as addition, without using standard arithmetic operators. It offers a unique perspective on understanding and applying bitwise operators to solve computational problems, showcasing the versatility and power of bit-level operations in programming.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-sum-of-two-integers-bit-manipulation</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-sum-of-two-integers-bit-manipulation</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 23 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the 3Sum Problem]]></title>
            <description><![CDATA[<p>The &quot;3Sum&quot; problem is a classic algorithmic challenge that requires finding all unique triplets in an array that add up to zero. This problem steps up from the simpler &quot;Two Sum&quot; problem and tests your ability to manipulate arrays and apply the two-pointer technique.</p>
<h2 id="the-problem">The Problem</h2>
<p>Given an array <code>nums</code> of integers, the task is to find all unique triplets in the array that sum up to zero.</p>
<h2 id="the-solution">The Solution</h2>
<p>Here&#39;s a JavaScript function that effectively solves the 3Sum problem:</p>
<pre><code class="language-javascript">function threeSum(nums) {
    nums.sort((a, b) =&gt; a - b);
    const triplets = [];

    for (let i = 0; i &lt; nums.length - 2; i++) {
        if (i &gt; 0 &amp;&amp; nums[i] === nums[i - 1]) continue;

        let left = i + 1, right = nums.length - 1;
        while (left &lt; right) {
            const sum = nums[i] + nums[left] + nums[right];

            if (sum === 0) {
                triplets.push([nums[i], nums[left], nums[right]]);
                while (nums[left] === nums[left + 1]) left++;
                while (nums[right] === nums[right - 1]) right--;
                left++;
                right--;
            } else if (sum &lt; 0) {
                left++;
            } else {
                right--;
            }
        }
    }
    return triplets;
}
</code></pre>
<h2 id="the-explanation">The Explanation</h2>
<ul>
<li><strong>Sort the Array</strong>: The array is sorted to use the two-pointer technique effectively.</li>
<li><strong>Iterate and Find Triplets</strong>: Loop through the array, for each element, use a left and right pointer to find triplets.</li>
<li><strong>Skip Duplicates</strong>: Skip over duplicate elements to avoid repeating triplets.</li>
<li><strong>Two-Pointer Technique</strong>: Adjust the left and right pointers to find different combinations that sum up to zero.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>This problem is a perfect example of the application of sorting and two-pointer techniques in solving complex array problems. It&#39;s often used in coding interviews to assess a candidate&#39;s problem-solving and array manipulation skills.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-3sum</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-3sum</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the Container With Most Water Problem]]></title>
            <description><![CDATA[<p>The &quot;Container With Most Water&quot; problem is a classic example of applying the two-pointer technique to find an optimal solution efficiently. This problem is common in coding interviews and challenges your understanding of array manipulation.</p>
<h2 id="the-problem">The Problem</h2>
<p>You are given an array <code>height</code>, representing the height of vertical lines on a chart. The task is to find the two lines that, together with the x-axis, form a container that can hold the maximum amount of water.</p>
<h2 id="the-solution">The Solution</h2>
<p>Here&#39;s a straightforward JavaScript implementation:</p>
<pre><code class="language-javascript">function maxArea(height) {
    let maxArea = 0, left = 0, right = height.length - 1;

    while (left &lt; right) {
        const width = right - left;
        const currentArea = Math.min(height[left], height[right]) * width;
        maxArea = Math.max(maxArea, currentArea);

        if (height[left] &lt; height[right]) {
            left++;
        } else {
            right--;
        }
    }

    return maxArea;
}
</code></pre>
<p>The solution uses two pointers, <code>left</code> and <code>right</code>, to traverse the array from both ends. The <code>maxArea</code> variable keeps track of the maximum area found so far. The <code>while</code> loop continues until the two pointers meet.<br>The <code>width</code> variable represents the width of the container. The <code>currentArea</code> variable represents the area of the container formed by the two pointers. The <code>Math.min</code> function is used to find the minimum height of the two pointers. The <code>Math.max</code> function is used to update the <code>maxArea</code> variable.<br>The <code>if</code> statement checks if the height of the left pointer is less than the height of the right pointer. If so, the left pointer is moved one step to the right. Otherwise, the right pointer is moved one step to the left.</p>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<ul>
<li><p><strong>Two-Pointer Technique</strong>: Start with two pointers, one at the beginning (<code>left</code>) and one at the end (<code>right</code>) of the array. These pointers represent potential boundaries of the water container.</p>
</li>
<li><p><strong>Calculate Area</strong>: At each step, calculate the area formed by the lines at the <code>left</code> and <code>right</code> pointers. The area is determined by the distance between the pointers (width) and the height of the shorter line.</p>
</li>
<li><p><strong>Update Max Area</strong>: Keep track of the maximum area encountered so far. If the current area is larger than the <code>maxArea</code>, update <code>maxArea</code>.</p>
</li>
<li><p><strong>Move Pointers</strong>: Move the pointer pointing to the shorter line towards the other pointer. This is because moving the shorter line could potentially find a taller line and thus increase the area.</p>
</li>
<li><p><strong>Repeat</strong>: Continue the process until the <code>left</code> and <code>right</code> pointers meet, meaning all potential pairs have been evaluated.</p>
</li>
<li><p><strong>Return Result</strong>: The <code>maxArea</code> at the end of the iteration process will be the maximum amount of water the container can store.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>This problem is an excellent demonstration of the two-pointer technique&#39;s effectiveness in solving array-based challenges. It particularly highlights how optimal solutions often involve comparing pairs of elements and adjusting strategies based on their comparison. The &quot;Container With Most Water&quot; problem is not just about understanding arrays, but also about grasping the significance of element positions and how they relate to an optimal solution.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-container-with-most-water</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-container-with-most-water</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Find Minimum in Rotated Sorted Array]]></title>
            <description><![CDATA[<p>The &quot;Find Minimum in Rotated Sorted Array&quot; problem is an intriguing search problem that involves finding the minimum element in a sorted array that has been rotated at some unknown pivot point.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given a rotated sorted array, the goal is to find the minimum element. The original array is sorted in ascending order but then rotated at some pivot.</p>
<h2 id="examples">Examples</h2>
<ol>
<li><p><strong>Input</strong>: <code>nums = [3,4,5,1,2]</code><br><strong>Output</strong>: <code>1</code><br><strong>Explanation</strong>: The original array was <code>[1,2,3,4,5]</code> rotated 3 times.</p>
</li>
<li><p><strong>Input</strong>: <code>nums = [4,5,6,7,0,1,2]</code><br><strong>Output</strong>: <code>0</code><br><strong>Explanation</strong>: The original array was <code>[0,1,2,4,5,6,7]</code> and it was rotated 4 times.</p>
</li>
</ol>
<h2 id="constraints">Constraints</h2>
<ul>
<li><code>1 &lt;= nums.length &lt;= 5000</code></li>
<li><code>-5000 &lt;= nums[i] &lt;= 5000</code></li>
<li>The array is sorted and rotated at some pivot.</li>
</ul>
<h2 id="binary-search-solution">Binary Search Solution</h2>
<p>The solution leverages a modified binary search due to the sorted nature of the array:</p>
<pre><code class="language-typescript">function findMin(nums: number[]): number {
    let left = 0;
    let right = nums.length - 1;

    while (left &lt; right) {
        let mid = Math.floor((left + right) / 2);

        if (nums[mid] &gt; nums[right]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }

    return nums[left];
}
</code></pre>
<h2 id="explanation">Explanation</h2>
<ul>
<li>The algorithm initiates a binary search. However, instead of searching for a specific value, it looks for the inflection point.</li>
<li>The inflection point is where we find the smallest element.</li>
<li>The logic in the binary search is modified to find this point by comparing the middle element with the rightmost element to decide which half of the array to continue the search.</li>
</ul>
<p>This problem is a classic example used in interviews to assess a candidate&#39;s proficiency in modifying and applying binary search in different scenarios.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-find-minimum-in-rotated-sorted-array</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-find-minimum-in-rotated-sorted-array</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Understanding the Maximum Product Subarray Problem]]></title>
            <description><![CDATA[<p>The &quot;Maximum Product Subarray&quot; problem is a notable challenge in dynamic programming, focusing on finding a contiguous subarray with the largest product in a given array.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an integer array <code>nums</code>, the task is to find the contiguous subarray within <code>nums</code> that has the largest product and return this product.</p>
<h2 id="unique-challenge">Unique Challenge</h2>
<p>The presence of negative numbers in the array adds a layer of complexity. The product of negative numbers can turn a seemingly small product into a large one, which is a key difference from sum-based problems.</p>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<pre><code class="language-typescript">function maxProduct(nums: number[]): number {
    if (nums.length === 0) return 0;

    let maxSoFar = nums[0];
    let minSoFar = nums[0];
    let result = maxSoFar;

    for (let i = 1; i &lt; nums.length; i++) {
        let curr = nums[i];
        let tempMax = Math.max(curr, Math.max(maxSoFar * curr, minSoFar * curr));
        minSoFar = Math.min(curr, Math.min(maxSoFar * curr, minSoFar * curr));

        maxSoFar = tempMax;
        result = Math.max(maxSoFar, result);
    }

    return result;
}
</code></pre>
<h2 id="explanation">Explanation</h2>
<ul>
<li><strong>Dynamic Programming Approach:</strong><ul>
<li>The algorithm keeps track of the maximum and minimum product up to each index, considering the impact of negative numbers.</li>
<li>At each step, it updates the maximum and minimum products based on the current number and the previous maximum and minimum products.</li>
<li>The result is continuously updated with the largest product found.</li>
</ul>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>This problem is an excellent example of dynamic programming&#39;s utility in handling complex array manipulation tasks, especially when dealing with both positive and negative elements.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-maximum-product-subarray</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-maximum-product-subarray</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Maximum Subarray Problem Solutions]]></title>
            <description><![CDATA[<p>The &quot;Maximum Subarray&quot; problem is a classic example in computer science, used to illustrate dynamic programming as well as divide and conquer strategies. It involves finding a contiguous subarray with the largest sum in a given array.</p>
<h2 id="dynamic-programming-solution">Dynamic Programming Solution</h2>
<p>The dynamic programming approach, also known as Kadane&#39;s algorithm, iteratively computes the maximum subarray sum ending at each position.</p>
<pre><code class="language-typescript">function maxSubArray(nums: number[]): number {
    let maxSub = nums[0];
    let curSum = 0;
    
    for (let num of nums) {
        if (curSum &lt; 0) {
            curSum = 0;
        }
        curSum += num;
        maxSub = Math.max(maxSub, curSum);
    }
    
    return maxSub;
}
</code></pre>
<h2 id="divide-and-conquer-solution">Divide and Conquer Solution</h2>
<p>The divide and conquer approach splits the array into two halves and recursively finds the maximum subarray sum in each half. It also considers the possibility of the maximum subarray crossing the midpoint.</p>
<pre><code class="language-typescript">function crossSum(nums: number[], left: number, right: number, mid: number): number {
    if (left === right) return nums[left];

    let leftSubsum = Number.NEGATIVE_INFINITY;
    let currSum = 0;
    for (let i = mid; i &gt; left - 1; --i) {
        currSum += nums[i];
        leftSubsum = Math.max(leftSubsum, currSum);
    }

    let rightSubsum = Number.NEGATIVE_INFINITY;
    currSum = 0;
    for (let i = mid + 1; i &lt; right + 1; ++i) {
        currSum += nums[i];
        rightSubsum = Math.max(rightSubsum, currSum);
    }

    return leftSubsum + rightSubsum;
}

function helper(nums: number[], left: number, right: number): number {
    if (left === right) return nums[left];

    const mid = Math.floor((left + right) / 2);

    const leftSum = helper(nums, left, mid);
    const rightSum = helper(nums, mid + 1, right);
    const crossSum = crossSum(nums, left, right, mid);

    return Math.max(Math.max(leftSum, rightSum), crossSum);
}

function maxSubArrayDivideAndConquer(nums: number[]): number {
    return helper(nums, 0, nums.length - 1);
}
</code></pre>
<h2 id="explanation">Explanation</h2>
<ul>
<li><strong>Dynamic Programming</strong>: This approach iteratively updates a running sum and maximum sum, resetting the running sum if it becomes negative.</li>
<li><strong>Divide and Conquer</strong>: This method recursively solves the problem in subarrays and finds the maximum sum that crosses the middle of the array.<br>Both methods offer a way to understand different algorithmic strategies and their applications in solving complex problems.</li>
</ul>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-maximum-subarray</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-maximum-subarray</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Product of Array Except Self]]></title>
            <description><![CDATA[<p>In many coding challenges, especially in array manipulation problems, one often encounters the need to compute the product of all elements in an array except the one at the current index. The <code>productExceptSelf</code> function is a classic example of such a problem, demonstrating an efficient approach without using division.</p>
<h2 id="the-function">The Function</h2>
<pre><code class="language-javascript">function productExceptSelf(nums: number[]): number[] {
    let res = new Array(nums.length).fill(nums[0]);
    
    let prefix = 1;
    for (let i = 0; i &lt; nums.length; i++) {
        res[i] = prefix;
        prefix *= nums[i];
    }
    
    let postfix = 1;
    for (let i = nums.length - 1; i &gt;= 0; i--) {
        res[i] *= postfix;
        postfix *= nums[i];
    }
    
    return res;
}
</code></pre>
<p>The &quot;Product of Array Except Self&quot; problem is a classic challenge often encountered in coding interviews. It tests a candidate&#39;s ability to manipulate arrays and optimize algorithms.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an array <code>nums</code> of <code>n</code> integers where <code>n &gt; 1</code>, the task is to return an array <code>output</code> such that <code>output[i]</code> is equal to the product of all the elements of <code>nums</code> except <code>nums[i]</code>.</p>
<h2 id="constraints-and-challenges">Constraints and Challenges</h2>
<ul>
<li>No division operation is allowed in the solution.</li>
<li>The goal is to achieve a linear runtime complexity, O(n).</li>
<li>A straightforward nested loop approach leads to O(n²) time complexity, which is inefficient.</li>
</ul>
<h2 id="techniques-for-solution">Techniques for Solution</h2>
<ol>
<li><p><strong>Prefix and Postfix Products</strong>:<br>This efficient approach involves two passes through the array:</p>
<ul>
<li><strong>Prefix Product</strong>: Traverse the array from left to right, calculating the cumulative product up to the current element. Store these products in a new array.</li>
<li><strong>Postfix Product</strong>: Traverse the array from right to left, calculating the cumulative product from the end to the current element. Multiply these with the prefix products in the new array.</li>
</ul>
</li>
<li><p><strong>Left and Right Product Lists</strong>:<br>Use two additional arrays to store products of all elements to the left and right of each element, and then multiply corresponding elements from these arrays for the final result. This method uses extra space.</p>
</li>
<li><p><strong>Optimized Space Approach</strong>:<br>Optimize the space complexity by using the output array for storing one of the lists (like left products) and a variable to track the right product during the second traversal.</p>
</li>
</ol>
<h2 id="example">Example</h2>
<p>Consider <code>nums = [1, 2, 3, 4]</code>. The expected output is <code>[24, 12, 8, 6]</code>.</p>
<ul>
<li>After the first pass (prefix): <code>[1, 1, 2, 6]</code>.</li>
<li>After the second pass (postfix): <code>[24, 12, 8, 6]</code>.</li>
</ul>
<p>This problem demonstrates the importance of array manipulation and optimizing solutions for better time and space efficiency.</p>
<h2 id="references">References</h2>
<p><a href="https://www.enjoyalgorithms.com/blog/product-of-array-except-self" target="_blank" rel="noopener noreferrer">https://www.enjoyalgorithms.com/blog/product-of-array-except-self</a></p>
<hr>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-product-of-array-except-self</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-product-of-array-except-self</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the Search in Rotated Sorted Array Problem]]></title>
            <description><![CDATA[<p>As someone who enjoys tackling complex algorithmic challenges, I often encounter problems that require a deep understanding of search algorithms and data manipulation. One such problem is the &quot;Search in Rotated Sorted Array,&quot; a frequent question in coding interviews. This post will guide you through understanding this problem and provide an efficient solution using JavaScript.</p>
<h3 id="understanding-the-problem">Understanding the Problem</h3>
<p>The &quot;Search in Rotated Sorted Array&quot; problem involves finding the index of a target number in a sorted array that has been rotated. It&#39;s a twist on the binary search algorithm, where the array is no longer strictly sorted in the conventional sense, but is instead rotated at an unknown pivot point.</p>
<h3 id="the-challenge">The Challenge</h3>
<p>Given an array <code>nums</code> that has been rotated and a target value, the task is to find the index of this target in <code>nums</code>, or return -1 if it does not exist.</p>
<h3 id="the-solution">The Solution</h3>
<p>Here&#39;s a JavaScript function to effectively solve this problem:</p>
<pre><code class="language-javascript">function search(nums, target) {
    let left = 0, right = nums.length - 1;
    
    while (left &lt;= right) {
        const mid = Math.floor((left + right) / 2);
        
        if (nums[mid] === target) return mid;
        
        // Check if the left half is sorted
        if (nums[left] &lt;= nums[mid]) {
            if (target &gt;= nums[left] &amp;&amp; target &lt; nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        // Right half is sorted
        else {
            if (target &gt; nums[mid] &amp;&amp; target &lt;= nums[right]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }
    
    return -1;
}
</code></pre>
<h3 id="how-it-works">How It Works</h3>
<ul>
<li><strong>Check Middle Element</strong>: At each step, check if the middle element is the target.</li>
<li><strong>Identify Sorted Half</strong>: Determine which half of the array is sorted.</li>
<li><strong>Refine Search</strong>: Based on the target’s value and the sorted half, adjust the search range.</li>
<li><strong>Iterate Until Found</strong>: Continue the process until the target is found or the range is empty.</li>
</ul>
<h3 id="conclusion">Conclusion</h3>
<p>This problem serves as an excellent example of how binary search can be adapted to less straightforward scenarios. It tests your ability to think critically about sorted arrays and how to navigate them when a typical sorted order is disrupted.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-search-in-rotated-sorted-array</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-search-in-rotated-sorted-array</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Fri, 22 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the 'Best Time to Buy and Sell Stock' Problem]]></title>
            <description><![CDATA[<p>In the world of algorithmic challenges, the &#39;Best Time to Buy and Sell Stock&#39; problem is a classic. It&#39;s a favorite in coding interviews, testing your ability to analyze trends within an array. In this post, we&#39;ll delve into what this problem entails and how to approach it using JavaScript.</p>
<h3 id="the-problem">The Problem</h3>
<p>The challenge is framed as follows: Given an array where each element represents the price of a stock on that day, find the maximum profit you can achieve. You are allowed to buy and sell only once. In other words, find the maximum difference between a later selling price and an earlier buying price.</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>This problem is not just about finding the maximum difference in an array; it&#39;s about understanding the nuances of timing in buying and selling—akin to real-world stock trading. It tests your grasp of array traversal and optimization.</p>
<h3 id="the-javascript-solution">The JavaScript Solution</h3>
<p>Here&#39;s a concise and efficient way to solve this problem in JavaScript:</p>
<pre><code class="language-javascript">/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let [buy, sell] = [0, 1];
    let maxProfit = 0;

    while (sell &lt; prices.length) {
        if (prices[buy] &lt; prices[sell]) {
            let profit = prices[sell] - prices[buy];
            maxProfit = Math.max(maxProfit, profit);
        } else {
            buy = sell;
        }

        sell++;
    }

    return maxProfit;
};
</code></pre>
<h3 id="breaking-down-the-solution">Breaking Down the Solution</h3>
<ul>
<li><strong>Initial Setup</strong>: We start with two pointers, <code>buy</code> and <code>sell</code>, representing the days to buy and sell the stock.</li>
<li><strong>Loop Through Prices</strong>: As we iterate through the array, we continuously calculate the profit (difference between selling and buying prices) and update the maximum profit.</li>
<li><strong>Optimize Buy Day</strong>: If we find a day with a lower price than our current buying day, we shift our buying day to this lower price day.</li>
<li><strong>Return Maximum Profit</strong>: After traversing the array, the maximum profit we&#39;ve calculated is returned.</li>
</ul>
<h3 id="key-takeaways">Key Takeaways</h3>
<ul>
<li><strong>Efficiency Matters</strong>: The solution uses a single pass over the array, ensuring an optimal time complexity.</li>
<li><strong>Pointer Technique</strong>: Using two pointers helps in comparing elements without nested loops, a handy technique in many coding problems.</li>
</ul>
<p>By understanding this approach, you&#39;re not just solving a problem; you&#39;re gaining insights into efficient data traversal and optimization—skills crucial for many coding challenges and real-world applications.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-best-time-to-buy-and-sell-stock</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-best-time-to-buy-and-sell-stock</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Thu, 21 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the 'Contains Duplicate' Problem in JavaScript]]></title>
            <description><![CDATA[<p>The &#39;Contains Duplicate&#39; problem is a fundamental question in coding interviews, focusing on array manipulation and data structure optimization. This problem asks you to determine if an array contains any duplicates. It&#39;s a great way to demonstrate efficient data handling in JavaScript. Here, we&#39;ll explore a concise solution to this problem.</p>
<h3 id="the-problem-statement">The Problem Statement</h3>
<p>Given an array of integers, <code>nums</code>, the task is to check if the array contains any duplicate elements. In other words, we need to see if any value appears at least twice in the array.</p>
<h3 id="why-its-important">Why It&#39;s Important</h3>
<p>This problem tests your ability to handle arrays and use JavaScript&#39;s built-in data structures, like <code>Set</code>, effectively. It&#39;s a common task that mirrors real-world scenarios where data uniqueness is crucial.</p>
<h3 id="javascript-solution-using-set">JavaScript Solution: Using Set</h3>
<p>Here&#39;s a simple and efficient JavaScript function to solve this problem:</p>
<pre><code class="language-javascript">/**
 * @param {number[]} nums
 * @return {boolean}
 */
var containsDuplicate = function(nums) {
    return new Set(nums).size !== nums.length;
};
</code></pre>
<h3 id="breaking-down-the-solution">Breaking Down the Solution</h3>
<ul>
<li><strong>Leverage <code>Set</code></strong>: JavaScript&#39;s <code>Set</code> object is a collection of unique values. By converting the array to a set, we automatically remove any duplicates.</li>
<li><strong>Compare Sizes</strong>: If the size of the set is different from the original array&#39;s length, it implies that duplicates were present and removed in the conversion process.</li>
</ul>
<h3 id="key-takeaways">Key Takeaways</h3>
<ul>
<li><strong>Simplicity and Efficiency</strong>: This solution is both simple and efficient, utilizing the powerful features of JavaScript&#39;s standard objects.</li>
<li><strong>Understanding Data Structures</strong>: Knowing the properties of different data structures, like a <code>Set</code>, is key in crafting optimized solutions.</li>
</ul>
<p>By grasping this approach, you not only solve the problem at hand but also enhance your understanding of JavaScript&#39;s data structures, a vital skill in many programming tasks and interviews.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-contains-duplicate</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-contains-duplicate</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Thu, 21 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Linked List Cycle: Detecting Loops in Data Structures]]></title>
            <description><![CDATA[<p>The &quot;Linked List Cycle&quot; problem involves identifying whether a cycle exists in a singly linked list.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Determine if a given singly linked list has a cycle in it. In a linked list with a cycle, a node&#39;s next pointer points to an earlier node, creating a loop.</p>
<h2 id="example">Example</h2>
<p>Consider a linked list where the <code>next</code> pointer of a node points back to a previous node, forming a loop. The challenge is to detect this loop.</p>
<h2 id="solution-approach---floyds-tortoise-and-hare-algorithm">Solution Approach - Floyd&#39;s Tortoise and Hare Algorithm</h2>
<pre><code class="language-typescript">class ListNode {
  val: number;
  next: ListNode | null;

  constructor(val?: number, next?: ListNode | null) {
      this.val = (val === undefined ? 0 : val);
      this.next = (next === undefined ? null : next);
  }
}

function hasCycle(head: ListNode | null): boolean {
  let slow: ListNode | null = head;
  let fast: ListNode | null = head;

  while (fast &amp;&amp; fast.next) {
      slow = slow ? slow.next : null;
      fast = fast.next ? fast.next.next : null;

      if (slow === fast) {
          return true; // Cycle detected
      }
  }

  return false; // No cycle found
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Two Pointers</strong>: Initialize two pointers, <code>slow</code> and <code>fast</code>. <code>slow</code> moves one step at a time, while <code>fast</code> moves two steps.</p>
</li>
<li><p><strong>Iterate Through List</strong>: Move through the list, with <code>slow</code> and <code>fast</code> progressing at their respective speeds.</p>
</li>
<li><p><strong>Detecting the Cycle</strong>: If there is a cycle, <code>slow</code> and <code>fast</code> will eventually meet at some node. If they do, return <code>true</code>.</p>
</li>
<li><p><strong>Termination Condition</strong>: If <code>fast</code> or <code>fast.next</code> becomes <code>null</code>, it means the list has no cycle, and we return <code>false</code>.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Linked List Cycle problem is a fundamental concept in data structures, particularly in understanding linked lists. Floyd&#39;s Tortoise and Hare algorithm provides an efficient way to detect cycles, demonstrating the importance of pointer manipulation and two-pointer techniques in algorithm design.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-linked-list-cycle</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-linked-list-cycle</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Wed, 20 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Set Matrix Zeroes: Efficient In-Place Modification]]></title>
            <description><![CDATA[<p>The &quot;Set Matrix Zeroes&quot; problem involves modifying a matrix in-place, setting entire rows and columns to zero where any element in them is zero.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an <code>m x n</code> matrix, if an element is 0, set its entire row and column to 0. Do it in-place.</p>
<h2 id="example">Example</h2>
<ul>
<li><p><strong>Input</strong>: Matrix<br>[<br>[1,1,1],<br>[1,0,1],<br>[1,1,1]<br>]</p>
</li>
<li><p><strong>Output</strong>:<br>[<br>[1,0,1],<br>[0,0,0],<br>[1,0,1]<br>]</p>
</li>
</ul>
<h2 id="solution-approach---space-optimized">Solution Approach - Space Optimized</h2>
<pre><code class="language-javascript">function setZeroes(matrix: number[][]): void {
  if (matrix.length === 0 || matrix[0].length === 0) return;
  
  let isCol = false;
  const R = matrix.length;
  const C = matrix[0].length;

  for (let i = 0; i &lt; R; i++) {
      if (matrix[i][0] === 0) isCol = true;
      for (let j = 1; j &lt; C; j++) {
          if (matrix[i][j] === 0) {
              matrix[i][0] = 0;
              matrix[0][j] = 0;
          }
      }
  }

  for (let i = 1; i &lt; R; i++) {
      for (let j = 1; j &lt; C; j++) {
          if (matrix[i][0] === 0 || matrix[0][j] === 0) matrix[i][j] = 0;
      }
  }

  if (matrix[0][0] === 0) {
      for (let j = 0; j &lt; C; j++) matrix[0][j] = 0;
  }

  if (isCol) {
      for (let i = 0; i &lt; R; i++) matrix[i][0] = 0;
  }
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Mark Zeroes</strong>: Iterate through the matrix, marking the first cell of each row and column that contains a zero.</p>
</li>
<li><p><strong>Set Rows and Columns</strong>: Use the marks to set entire rows and columns to zero.</p>
</li>
<li><p><strong>Handle First Row and Column</strong>: Special handling for the first row and column to avoid overriding the marks.</p>
</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Set Matrix Zeroes problem is a valuable exercise in in-place array manipulation. It requires careful consideration to avoid unintended side effects while modifying the matrix.</p>
<p>The algorithm achieves constant space complexity (O(1)) by using the first row and the first column of the matrix itself to store information about which rows and columns should be zeroed.</p>
<p>Here’s a breakdown of how this is achieved:</p>
<p>First Pass: Iterate through the matrix and use the first cell of each row and column to mark whether that row or column should be set to zero. This requires two special checks:</p>
<p>Determine if the first row should be set to zero based on the cells in the first row.<br>Determine if the first column should be set to zero based on the cells in the first column.<br>Second Pass: Use the marks in the first row and first column to set the appropriate rows and columns to zero. Skip the first row and first column in this pass.</p>
<p>Final Step: Based on the checks from the first step, set the first row and/or first column to zero if needed.</p>
<p>This approach only uses a constant amount of additional space (for variables like isCol and loop counters) and modifies the matrix in place.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/set-matrix-zeroes</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/set-matrix-zeroes</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Wed, 20 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Solving the Two Sum Problem]]></title>
            <description><![CDATA[<p>As a computer science enthusiast, I often come across intriguing problems that not only challenge my coding skills<br>but also enhance my problem-solving abilities. One such classic problem is the &quot;Two Sum&quot; problem, a common interview<br>question and a great exercise for anyone looking to improve their programming acumen. In this post,<br>I&#39;ll walk you through what the Two Sum problem is, why it&#39;s important, and how to solve it using JavaScript.</p>
<p>The Two Sum problem is simple in its statement: Given an array of integers nums and an integer target,<br>return indices of the two numbers such that they add up to target. This problem tests your understanding of array manipulation and hashing concepts.<br>It&#39;s a fundamental question in algorithm design, often used to gauge a candidate&#39;s ability to work with data structures.</p>
<h2 id="understanding-the-problem">Understanding the Problem</h2>
<p>The key to solving the Two Sum problem lies in understanding how to efficiently find two numbers in the array that sum up to the target value. A brute force approach would involve checking each pair of numbers, but this is inefficient, especially for large arrays. A more efficient approach involves using a hash table to store and quickly look up the complement of each number.</p>
<h2 id="the-solution">The Solution</h2>
<p>Here&#39;s a TypeScript function that solves the Two Sum problem:</p>
<pre><code class="language-typescript">export function twoSum(nums: number[], target: number): number[] {
  const hash: { [key: number]: number } = {};
  for (let i = 0; i &lt; nums.length; i++) {
    const diff = target - nums[i];
    if (diff in hash) {
      return [hash[diff], i];
    }
    hash[nums[i]] = i;
  }

  return [];
}
</code></pre>
<p>Here&#39;s a JavaScript function that solves the Two Sum problem:</p>
<pre><code class="language-javascript">/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    const map = new Map();

    for (let i = 0; i &lt; nums.length; i++) {
        const diff = map.get(target - nums[i]);

        if (diff !== undefined) {
            return [diff, i]
        }

        map.set(nums[i], i);
    }
};
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<p>Initialize a Hash Table: We create a hash table (or object in JavaScript) to store each number&#39;s index as we iterate through the array.</p>
<p>Iterate Through the Array: We loop through each element in the array.</p>
<p>Calculate the Difference: For each element, we calculate the difference between the target and the current element. This difference is the value we need to find in the array to get a pair that sums to the target.</p>
<p>Check the Hash Table: We check if this difference already exists in our hash table. If it does, it means we have found a pair that adds up to the target. We return the indices of these two elements.</p>
<p>Store in the Hash Table: If the difference is not in the hash table, we add the current element and its index to the hash table and continue the loop.</p>
<p>Return Empty if No Solution: If no pair adds up to the target, we return an empty array.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-two-sum</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-two-sum</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Wed, 20 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Blind 75 LeetCode Questions]]></title>
            <description><![CDATA[<p>LeetCode is a popular platform for practicing coding problems, especially when preparing for technical interviews. The &quot;Blind 75&quot; is a collection of 75 carefully selected questions from LeetCode that are particularly useful for interview preparation. These questions cover a range of topics and difficulty levels, and they are chosen based on their frequency and importance in real interviews.</p>
<p>This collection is divided into several categories, such as arrays, strings, linked lists, trees, dynamic programming, and more. Each category contains a mix of easy, medium, and hard problems, allowing you to gradually build your skills.</p>
<h2 id="array">Array</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/two-sum/" target="_blank" rel="noopener noreferrer">Two Sum</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> HashMap <a href="/blog/solving-two-sum" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/" target="_blank" rel="noopener noreferrer">Best Time to Buy and Sell Stock</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Two Pointer <a href="/blog/solving-best-time-to-buy-and-sell-stock" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/contains-duplicate/" target="_blank" rel="noopener noreferrer">Contains Duplicate</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> HashSet <a href="/blog/solving-contains-duplicate" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/product-of-array-except-self/" target="_blank" rel="noopener noreferrer">Product of Array Except Self</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Prefix and Suffix product array <a href="/blog/solving-product-of-array-except-self" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/maximum-subarray/" target="_blank" rel="noopener noreferrer">Maximum Subarray</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Kadane&#39;s algorithm (Dynamic Programming) <a href="/blog/solving-maximum-subarray" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/maximum-product-subarray/" target="_blank" rel="noopener noreferrer">Maximum Product Subarray</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Kadane&#39;s algorithm (Dynamic Programming) <a href="/blog/solving-maximum-product-subarray" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/" target="_blank" rel="noopener noreferrer">Find Minimum in Rotated Sorted Array</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Binary Search <a href="/blog/solving-find-minimum-in-rotated-sorted-array" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/search-in-rotated-sorted-array/" target="_blank" rel="noopener noreferrer">Search in Rotated Sorted Array</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Binary Search <a href="/blog/solving-search-in-rotated-sorted-array" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/3sum/" target="_blank" rel="noopener noreferrer">3Sum</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Two Pointer <a href="/blog/solving-3sum" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/container-with-most-water/" target="_blank" rel="noopener noreferrer">Container With Most Water</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Two Pointer <a href="/blog/solving-container-with-most-water" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="binary">Binary</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/sum-of-two-integers/" target="_blank" rel="noopener noreferrer">Sum of Two Integers</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Bit Manipulation <a href="/blog/solving-sum-of-two-integers-bit-manipulation" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/number-of-1-bits/" target="_blank" rel="noopener noreferrer">Number of 1 Bits</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Bit Manipulation <a href="/blog/solving-number-of-1-bits" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/counting-bits/" target="_blank" rel="noopener noreferrer">Counting Bits</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Bit Manipulation (Dynamic Programming) <a href="/blog/solving-counting-bits" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/missing-number/" target="_blank" rel="noopener noreferrer">Missing Number</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Bit Manipulation <a href="/blog/solving-missing-number" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/reverse-bits/" target="_blank" rel="noopener noreferrer">Reverse Bits</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Bit Manipulation <a href="/blog/solving-reverse-bits" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="dynamic-programming">Dynamic Programming</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/climbing-stairs/" target="_blank" rel="noopener noreferrer">Climbing Stairs</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Dynamic Programming <a href="/blog/solving-climbing-stairs" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/coin-change/" target="_blank" rel="noopener noreferrer">Coin Change</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-coin-change" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-increasing-subsequence/" target="_blank" rel="noopener noreferrer">Longest Increasing Subsequence</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-longest-increasing-subsequence" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-common-subsequence/" target="_blank" rel="noopener noreferrer">Longest Common Subsequence</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-longest-common-subsequence" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/word-break/" target="_blank" rel="noopener noreferrer">Word Break Problem</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-word-break" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/combination-sum-iv/" target="_blank" rel="noopener noreferrer">Combination Sum</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-combination-sum-iv" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/house-robber/" target="_blank" rel="noopener noreferrer">House Robber</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-house-robber" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/house-robber-ii/" target="_blank" rel="noopener noreferrer">House Robber II</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-house-robber-ii" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/decode-ways/" target="_blank" rel="noopener noreferrer">Decode Ways</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-decode-ways" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/unique-paths/" target="_blank" rel="noopener noreferrer">Unique Paths</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-unique-paths" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/jump-game/" target="_blank" rel="noopener noreferrer">Jump Game</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Dynamic Programming <a href="/blog/solving-jump-game" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="graph">Graph</h2>
<ul>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/clone-graph/" target="_blank" rel="noopener noreferrer">Clone Graph</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-clone-graph" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/course-schedule/" target="_blank" rel="noopener noreferrer">Course Schedule</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Topological Sort <a href="/blog/solving-course-schedule" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/pacific-atlantic-water-flow/" target="_blank" rel="noopener noreferrer">Pacific Atlantic Water Flow</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-pacific-atlantic-water-flow" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/number-of-islands/" target="_blank" rel="noopener noreferrer">Number of Islands</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-number-of-islands" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-consecutive-sequence/" target="_blank" rel="noopener noreferrer">Longest Consecutive Sequence</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-longest-consecutive-sequence" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/alien-dictionary/" target="_blank" rel="noopener noreferrer">Alien Dictionary (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Topological Sort <a href="/blog/solving-alien-dictionary" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/graph-valid-tree/" target="_blank" rel="noopener noreferrer">Graph Valid Tree (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-graph-valid-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/" target="_blank" rel="noopener noreferrer">Number of Connected Components in an Undirected Graph (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Graph Traversal <a href="/blog/solving-number-of-connected-components-in-an-undirected-graph" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="interval">Interval</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/insert-interval/" target="_blank" rel="noopener noreferrer">Insert Interval</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Interval <a href="/blog/solving-insert-interval" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/merge-intervals/" target="_blank" rel="noopener noreferrer">Merge Intervals</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Interval <a href="/blog/solving-merge-intervals" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/non-overlapping-intervals/" target="_blank" rel="noopener noreferrer">Non-overlapping Intervals</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Interval <a href="/blog/solving-non-overlapping-intervals" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/meeting-rooms/" target="_blank" rel="noopener noreferrer">Meeting Rooms (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Interval <a href="/blog/solving-meeting-rooms" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/meeting-rooms-ii/" target="_blank" rel="noopener noreferrer">Meeting Rooms II (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Interval <a href="/blog/solving-meeting-rooms-ii" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="linked-list">Linked List</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/reverse-linked-list/" target="_blank" rel="noopener noreferrer">Reverse a Linked List</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Linked List <a href="/blog/solving-reverse-linked-list" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/linked-list-cycle/" target="_blank" rel="noopener noreferrer">Detect Cycle in a Linked List</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Linked List Two Pointers <a href="/blog/solving-detect-cycle-in-a-linked-list" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/merge-two-sorted-lists/" target="_blank" rel="noopener noreferrer">Merge Two Sorted Lists</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Linked List <a href="/blog/solving-merge-two-sorted-lists" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/merge-k-sorted-lists/" target="_blank" rel="noopener noreferrer">Merge K Sorted Lists</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Linked List Divide and Conquer <a href="/blog/solving-merge-k-sorted-lists" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/remove-nth-node-from-end-of-list/" target="_blank" rel="noopener noreferrer">Remove Nth Node From End Of List</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Linked List <a href="/blog/solving-remove-nth-node-from-end-of-list" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/reorder-list/" target="_blank" rel="noopener noreferrer">Reorder List</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Linked List <a href="/blog/solving-reorder-list" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="matrix">Matrix</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/set-matrix-zeroes/" target="_blank" rel="noopener noreferrer">Set Matrix Zeroes</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Matrix <a href="/blog/solving-set-matrix-zeroes" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/spiral-matrix/" target="_blank" rel="noopener noreferrer">Spiral Matrix</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Matrix right,left,top,bottom <a href="/blog/solving-spiral-matrix" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/rotate-image/" target="_blank" rel="noopener noreferrer">Rotate Image</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Matrix change rows with columns then rotate each row <a href="/blog/solving-rotate-image" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/word-search/" target="_blank" rel="noopener noreferrer">Word Search</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Matrix DFS <a href="/blog/solving-word-search" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="string">String</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/" target="_blank" rel="noopener noreferrer">Longest Substring Without Repeating Characters</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Sliding Window <a href="/blog/solving-longest-substring-without-repeating-characters" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-repeating-character-replacement/" target="_blank" rel="noopener noreferrer">Longest Repeating Character Replacement</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Sliding Window <a href="/blog/solving-longest-repeating-character-replacement" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/minimum-window-substring/" target="_blank" rel="noopener noreferrer">Minimum Window Substring</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Sliding Window <a href="/blog/solving-minimum-window-substring" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/valid-anagram/" target="_blank" rel="noopener noreferrer">Valid Anagram</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> HashMap <a href="/blog/solving-valid-anagram" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/group-anagrams/" target="_blank" rel="noopener noreferrer">Group Anagrams</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> HashMap <a href="/blog/solving-group-anagrams" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/valid-parentheses/" target="_blank" rel="noopener noreferrer">Valid Parentheses</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Stack <a href="/blog/solving-valid-parentheses" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/valid-palindrome/" target="_blank" rel="noopener noreferrer">Valid Palindrome</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Two Pointer <a href="/blog/solving-valid-palindrome" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/longest-palindromic-substring/" target="_blank" rel="noopener noreferrer">Longest Palindromic Substring</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Two Pointer expand around center <a href="/blog/solving-longest-palindromic-substring" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/palindromic-substrings/" target="_blank" rel="noopener noreferrer">Palindromic Substrings</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Two Pointer <a href="/blog/solving-palindromic-substrings" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input disabled="" type="checkbox"> <a href="https://leetcode.com/problems/encode-and-decode-strings/" target="_blank" rel="noopener noreferrer">Encode and Decode Strings (Leetcode Premium)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> String <a href="/blog/solving-encode-and-decode-strings" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="tree">Tree</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/maximum-depth-of-binary-tree/" target="_blank" rel="noopener noreferrer">Maximum Depth of Binary Tree</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Tree Traversal <a href="/blog/solving-maximum-depth-of-binary-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/same-tree/" target="_blank" rel="noopener noreferrer">Same Tree</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Tree Traversal <a href="/blog/solving-same-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/invert-binary-tree/" target="_blank" rel="noopener noreferrer">Invert/Flip Binary Tree</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Tree Traversal <a href="/blog/solving-invert-binary-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/binary-tree-maximum-path-sum/" target="_blank" rel="noopener noreferrer">Binary Tree Maximum Path Sum</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Tree Traversal <a href="/blog/solving-binary-tree-maximum-path-sum" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/binary-tree-level-order-traversal/" target="_blank" rel="noopener noreferrer">Binary Tree Level Order Traversal</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-binary-tree-level-order-traversal" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/serialize-and-deserialize-binary-tree/" target="_blank" rel="noopener noreferrer">Serialize and Deserialize Binary Tree</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Tree Traversal <a href="/blog/solving-serialize-and-deserialize-binary-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/subtree-of-another-tree/" target="_blank" rel="noopener noreferrer">Subtree of Another Tree</a> &lt;span style={{color: &#39;green&#39;}}&gt;(Easy)</span> Tree Traversal <a href="/blog/solving-subtree-of-another-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/" target="_blank" rel="noopener noreferrer">Construct Binary Tree from Preorder and Inorder Traversal</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-construct-binary-tree-from-preorder-and-inorder-traversal" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/validate-binary-search-tree/" target="_blank" rel="noopener noreferrer">Validate Binary Search Tree</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-validate-binary-search-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/kth-smallest-element-in-a-bst/" target="_blank" rel="noopener noreferrer">Kth Smallest Element in a BST</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-kth-smallest-element-in-a-bst" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/" target="_blank" rel="noopener noreferrer">Lowest Common Ancestor of BST</a> &lt;span style={{color: &#39;oragne&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-lowest-common-ancestor-of-bst" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/implement-trie-prefix-tree/" target="_blank" rel="noopener noreferrer">Implement Trie (Prefix Tree)</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-implement-trie-prefix-tree" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/add-and-search-word-data-structure-design/" target="_blank" rel="noopener noreferrer">Add and Search Word</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Tree Traversal <a href="/blog/solving-design-add-and-search-words-data-structure" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/word-search-ii/" target="_blank" rel="noopener noreferrer">Word Search II</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Tree Traversal <a href="/blog/solving-word-search-ii" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<hr>
<h2 id="heap">Heap</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/merge-k-sorted-lists/" target="_blank" rel="noopener noreferrer">Merge K Sorted Lists</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Heap <a href="/blog/solving-merge-k-sorted-lists" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/top-k-frequent-elements/" target="_blank" rel="noopener noreferrer">Top K Frequent Elements</a> &lt;span style={{color: &#39;orange&#39;}}&gt;(Medium)</span> Heap <a href="/blog/solving-top-k-frequent-elements" target="_blank" rel="noopener noreferrer">Solution</a></li>
<li><input checked="" disabled="" type="checkbox"> <a href="https://leetcode.com/problems/find-median-from-data-stream/" target="_blank" rel="noopener noreferrer">Find Median from Data Stream</a> &lt;span style={{color: &#39;red&#39;}}&gt;(Hard)</span> Heap <a href="/blog/solving-find-median-from-data-stream" target="_blank" rel="noopener noreferrer">Solution</a></li>
</ul>
<h2 id="important-link">Important Link:</h2>
<p><a href="https://hackernoon.com/14-patterns-to-ace-any-coding-interview-question-c5bb3357f6ed" target="_blank" rel="noopener noreferrer">14 Patterns to Ace Any Coding Interview Question</a></p>
<h3 id="how-to-use-this-list">How to Use This List</h3>
<ul>
<li><strong>Start with Basics</strong>: Begin with easier problems to build your confidence.</li>
<li><strong>Focus on Patterns</strong>: Identify common patterns and algorithms.</li>
<li><strong>Practice Regularly</strong>: Consistency is key in problem-solving.</li>
<li><strong>Review Solutions</strong>: Understand not just the how, but also the why behind each solution.</li>
<li><strong>Mock Interviews</strong>: Use these problems to simulate real interview scenarios.</li>
</ul>
<h3 id="resources">Resources</h3>
<ul>
<li><a href="https://leetcode.com" target="_blank" rel="noopener noreferrer">LeetCode</a></li>
<li><a href="https://leetcode.com/discuss/general-discussion/460599/blind-75-leetcode-questions" target="_blank" rel="noopener noreferrer">Blind 75 Discussion Forum</a></li>
<li><a href="https://www.someUsefulResource.com" target="_blank" rel="noopener noreferrer">Coding Interview Resources</a></li>
<li><a href="https://seanprashad.com/leetcode-patterns/" target="_blank" rel="noopener noreferrer">LeetCode Patterns</a></li>
<li><a href="https://leetcode.com/explore/" target="_blank" rel="noopener noreferrer">LeetCode Explore</a></li>
<li><a href="https://docs.google.com/spreadsheets/d/1A2PaQKcdwO_lwxz9bAnxXnIQayCouZP6d-ENrBz_NXc/edit#gid=0" target="_blank" rel="noopener noreferrer">Blind 75 spreadsheet</a></li>
<li><a href="https://emre.me/categories/#coding-patterns" target="_blank" rel="noopener noreferrer">Coding Patterns</a></li>
</ul>
<p>Remember, the goal is not just to solve all 75 problems, but to understand the underlying principles and patterns that will enable you to tackle any new problem with confidence.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/blind-75-leetcode-questions</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/blind-75-leetcode-questions</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Tue, 19 Dec 2023 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building a blog with Next.js 14 and React Server Components]]></title>
            <description><![CDATA[<p>I&#39;ve been tinkering with this website and the <a href="https://beta.nextjs.org" target="_blank" rel="noopener noreferrer">Next.js 13 App Router</a> for a while now,<br>and it&#39;s been a great experience, especially in the last few months. But I&#39;ve seen some confusion around<br>how to use the new features and React Server Components, so I wrote up an outline on building this website.</p>
<p><Note> This post has been updated for <a href="https://nextjs.org/blog/next-14" target="_blank" rel="noopener noreferrer">Next.js 14.</a> </Note></p>
<p>To address the React-sized elephant in the room:<br>you do not need this fancy setup to build a blog.<br>HTML and CSS may be a better choice for you, but I&#39;d find little fun in that, and I&#39;m a strong believer in having a website to experiment with.</p>
<p>To set a few expectations, here&#39;s what this post <strong>won&#39;t</strong> do:</p>
<ul>
<li>Act as documentation for Next.js or React</li>
<li>Be a 100% code-complete tutorial. You&#39;ll need to fill in some gaps yourself.<ul>
<li>You can always reference <a href="https://github.com/maxleiter/maxleiter.com" target="_blank" rel="noopener noreferrer">this website&#39;s source code</a>.</li>
<li>There are file trees included with links to the source code.</li>
</ul>
</li>
</ul>
<p>And here&#39;s what it <strong>will</strong> do:</p>
<ul>
<li>Show you real-world examples involving React Server Components and the App Router.</li>
<li>Guide you in spinning up your own blog with Next.js 13 and React Server Components with great SEO and performance.<ul>
<li>I say static first because while you can opt into <a href="https://beta.nextjs.org/docs/rendering/static-and-dynamic-rendering" target="_blank" rel="noopener noreferrer">dynamic rendering</a> everything presented here can result in a fully static no-JavaScript site.</li>
</ul>
</li>
<li>Demonstrate how to enable writing in markdown with <a href="https://mdxjs.com/" target="_blank" rel="noopener noreferrer">MDX</a> and <a href="https://github.com/hashicorp/next-mdx-remote#react-server-components-rsc--nextjs-app-directory-support" target="_blank" rel="noopener noreferrer">next-mdx-remote/rsc</a><ul>
<li>We&#39;ll use <a href="https://github.com/code-hike/bright" target="_blank" rel="noopener noreferrer">Bright</a> for server-side syntax highlighting.</li>
</ul>
</li>
<li>Act as a launching point for your own experimentation and exploration.</li>
</ul>
<p>Now that that&#39;s out of the way:</p>
<h3 id="table-of-contents">Table of Contents</h3>
<h2 id="set-up-the-project">Set up the project</h2>
<p>First, we&#39;ll need to create a new Next.js project. You can launch the setup wizard with <code>npx create-next-app</code>:</p>
<pre><code class="language-bash">npx create-next-app --experimental-app
</code></pre>
<Note>
  If you want to migrate an existing project, refer to the [Next.js installation
  documentation](https://beta.nextjs.org/docs/installation).
</Note>

<p>Hit <code>y</code> (or <code>n</code>, I&#39;m not your boss) a few times to complete the wizard.</p>
<h2 id="file-structure">File structure</h2>
<p>The easiest way I&#39;ve found to thinking about structuring App Router applications is from a top-down approach.<br>Think of your general path structure, then start with your highest level &#39;scope&#39; (layout) and work your way down.</p>
<p>In our case, we&#39;ll have a <a href="/" target="_blank" rel="noopener noreferrer">home page</a>. Let&#39;s also add a <a href="/projects" target="_blank" rel="noopener noreferrer">projects page</a> and an <a href="/about" target="_blank" rel="noopener noreferrer">about page</a>.<br>We&#39;ll cover the blog in the next section.</p>
<p>In general, a page will look like this:</p>
<pre><code class="language-tsx">// page.tsx
export default function Page() {
  return &lt;&gt;Your content here&lt;/&gt;
}
</code></pre>
<p>In my case, the three pages we&#39;re making all look the same minus their content, so they seem like a strong candidate for sharing a layout.</p>
<p>A Layout will look something like this:</p>
<pre><code class="language-tsx">// layout.tsx
export default function Layout({ children }: PropsWithChildren) {
  return (
    &lt;&gt;
      // Your layout content here
      {children}
      // Or here
    &lt;/&gt;
  )
}
</code></pre>
<p>Knowing all of this, I chose to create four files: <code>app/layout.tsx</code>, <code>app/page.tsx</code>, <code>app/projects/page.tsx</code>, and <code>app/about/page.tsx</code>.<br>The layout will apply to all pages, and each page file will contain it&#39;s own content.</p>
<p>I ran into one small issue with this approach: the home page doesn&#39;t need a &lt;span style={{ position: &#39;relative&#39;, top: 4 }}&gt;<HomeIcon /></span> icon, but the other pages do.<br>It doesn&#39;t make much sense to include that in the home page, but all the other pages should have it,<br>so we&#39;ll keep it out of the root layout and create a <a href="https://beta.nextjs.org/docs/routing/defining-routes#route-groups" target="_blank" rel="noopener noreferrer">Route Group</a> with it&#39;s own nested layout layout to only apply to the other pages.</p>
<p>First, lets create our <code>app/(subpages)/components</code> directory and create a quick header only for the subpages:</p>
<pre><code class="language-tsx">// app/(subpages)components/header.tsx
import Link from &#39;next/link&#39;
import { HomeIcon } from &#39;react-feather&#39;

export default function Header() {
  return (
    &lt;header&gt;
      &lt;Link href=&quot;/&quot;&gt;
        &lt;HomeIcon /&gt;
      &lt;/Link&gt;
      // If you want to add a Client Component here like a theme switcher, mark that
      // component with &quot;use client&quot; and leave the majority of the header as an RSC
    &lt;/header&gt;
  )
}
</code></pre>
<p>And use it in our <code>app/(subpages)/layout.tsx</code>:</p>
<pre><code class="language-tsx">// app/(subpages)/layout.tsx
import Header from &#39;./components/header&#39;

export default function SubLayout({ children }) {
  return (
    &lt;&gt;
      &lt;Header /&gt;
      {children}
    &lt;/&gt;
  )
}
</code></pre>
<p>With the header in place, you now have a nested layout for subpages and blog posts.</p>
<p>Let&#39;s go ahead and create our files and directories:</p>
<Note>
  You can click any of the files in a file tree to view the source code on
  GitHub.
</Note>

<FileTree>
  <Folder name="app" open>
    <Folder 
      name="components" 
      open 
      note="contains our general components" 
    >
    </Folder>
    <File
      name="layout.tsx"
      type="layout"
      note="contains our <head> and <body>"
      url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/layout.tsx"
    />
    <File
      name="page.tsx"
      type="page"
      note="contains our Home Page"
      url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/page.tsx"
    />
    <Folder
      name="(subpages)"
      open
      note="route groups aren't included in the URL"
    >    
      <Folder 
        name="components" 
        open
      >
        <File 
          name="header.tsx" 
          type="component" 
          url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/components/header.tsx"
          note="<Header />"
        />
      </Folder>
      <File 
        name="layout.tsx" 
        type="layout" 
        note="contains our <Header />" 
        url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/layout.tsx" 
      />
      <Folder name="about" open>
        <File 
          name="page.tsx" 
          type="page" 
          url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/about/page.tsx"
          />
      </Folder>
      <Folder name="projects">
        <File 
          name="page.tsx" 
          type="page"
          url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/projects/page.tsx" />
      </Folder>
    </Folder>

  </Folder>
</FileTree>

<h2 id="a-blog-needs-posts">A blog needs posts</h2>
<h3 id="routing-with-dynamic-segments">Routing with dynamic segments</h3>
<p>For our blog posts like this one, we&#39;ll want <code>/blog/[slug]</code> to be a page that displays a single blog post, and we want it to have it&#39;s own footer to link to other posts.<br>It sure seems like the footer should live inside the <code>/blog/[slug]</code> layout. The <code>[slug]</code> in the URL is referred to as a <a href="https://beta.nextjs.org/docs/routing/defining-routes#dynamic-segments" target="_blank" rel="noopener noreferrer">Dynamic Segment</a>.</p>
<FileTree>
  <Folder name="blog" open>
    <Folder name="[slug]" open>
      <Folder name="components" open>
        <File
          name="footer.tsx"
          type="component"
          note="<BlogPostFooter />"
          url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/blog/%5Bslug%5D/post/navigation.tsx"
        />
      </Folder>
      <File
        name="layout.tsx"
        type="layout"
        note="renders <BlogPostFooter />"
        url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/blog/%5Bslug%5D/layout.tsx"
      />
      <File
        name="page.tsx"
        type="page"
        url="https://github.com/MaxLeiter/maxleiter.com/blob/master/app/(subpages)/blog/%5Bslug%5D/page.tsx"
      />
    </Folder>
  </Folder>
</FileTree>

<p>But how do we render markdown files in our blog posts?</p>
<h3 id="fetching-and-rendering-markdown">Fetching and rendering markdown</h3>
<p>The official Next.js documentation has a <a href="https://beta.nextjs.org/docs/guides/mdx#mdx" target="_blank" rel="noopener noreferrer">great guide</a> for using MDX with all your pages.<br>Sometimes you want to render content from a remote source though, like a <abbr title="Content Management System">CMS</abbr>.<br>In my case, for niche specific reasons, I want to keep my markdown separate from the Next.js project, so I&#39;ll be using <code>next-mdx-remote</code> and it&#39;s experimental React Server Components support.</p>
<p>A lot of the code is the same if you want to apply it to your own project, so just follow along with the code snippets.</p>
<h4 id="fetching-your-posts">Fetching your posts</h4>
<p>You need to fetch your posts from somewhere before you can render them.<br>There&#39;s a lot of ways to do this. Here&#39;s a simplified but functional version of mine loading them from the file system:</p>
<pre><code class="language-tsx">import matter from &#39;gray-matter&#39;
import path from &#39;path&#39;
import type { Post } from &#39;./types&#39;
import fs from &#39;fs/promises&#39;
import { cache } from &#39;react&#39;

// `cache` is a React 18 feature that allows you to cache a function for the lifetime of a request.
// this means getPosts() will only be called once per page build, even though we may call it multiple times
// when rendering the page.
export const getPosts = cache(async () =&gt; {
  const posts = await fs.readdir(&#39;./posts/&#39;)

  return Promise.all(
    posts
      .filter((file) =&gt; path.extname(file) === &#39;.mdx&#39;)
      .map(async (file) =&gt; {
        const filePath = `./posts/${file}`
        const postContent = await fs.readFile(filePath, &#39;utf8&#39;)
        const { data, content } = matter(postContent)

        if (data.published === false) {
          return null
        }

        return { ...data, body: content } as Post
      })
  )
})

export async function getPost(slug: string) {
  const posts = await getPosts()
  return posts.find((post) =&gt; post.slug === slug)
}

export default getPosts

// Usage:
const posts = await getPosts()
const post = await getPost(&#39;my-post&#39;)
</code></pre>
<p>Because <code>getPosts</code> is cached, you can call <code>getPost</code> multiple times in your layout tree without worrying about a network waterfall.</p>
<h4 id="rendering-your-posts">Rendering your posts</h4>
<p>Now that we have our posts, we can render them.</p>
<p>First, we need to setup MDX with any remark and rehype plugins. All the plugins are optional, but I&#39;ve included the ones I use.</p>
<pre><code class="language-tsx">// app/(subpages)/blog/[slug]/components/post-body.tsx
import { MDXRemote } from &#39;next-mdx-remote/rsc&#39;

import remarkGfm from &#39;remark-gfm&#39;
import rehypeSlug from &#39;rehype-slug&#39;
import rehypeAutolinkHeadings from &#39;rehype-autolink-headings&#39;
import remarkA11yEmoji from &#39;@fec/remark-a11y-emoji&#39;
import remarkToc from &#39;remark-toc&#39;
import { mdxComponents } from &#39;./markdown-components&#39;

export function PostBody({ children }: { children: string }) {
  return (
    &lt;MDXRemote
      source={children}
      options={{
        mdxOptions: {
          remarkPlugins: [
            // Adds support for GitHub Flavored Markdown
            remarkGfm,
            // Makes emojis more accessible
            remarkA11yEmoji,
            // generates a table of contents based on headings
            remarkToc,
          ],
          // These work together to add IDs and linkify headings
          rehypePlugins: [rehypeSlug, rehypeAutolinkHeadings],
        },
      }}
      components={mdxComponents}
    /&gt;
  )
}
</code></pre>
<p>You may notice the <code>components={mdxComponents}</code> prop. This is where we pass in our custom components that we want to use in our markdown files.<br>For using with Next.js, we probably want to use the official <code>next/link</code> and <code>next/image</code> components to opt into client side routing and image optimization.<br>This is also where I&#39;ve defined the components like the file trees in this post.</p>
<pre><code class="language-tsx">// app/(subpages)/blog/[slug]/components/markdown-components.tsx
import Link from &#39;next/link&#39;
import Image from &#39;next/image&#39;

export const mdxComponents: MDXComponents = {
  a: ({ children, ...props }) =&gt; {
    return (
      &lt;Link {...props} href={props.href || &#39;&#39;}&gt;
        {children}
      &lt;/Link&gt;
    )
  },
  img: ({ children, props }) =&gt; {
    // You need to do some work here to get the width and height of the image.
    // See the details below for my solution.
    return &lt;Image {...props} /&gt;
  },
  // any other components you want to use in your markdown
}
</code></pre>
<details>
<summary>{"How I get the width and height of an image"}</summary>

<p>There&#39;s probably a better way to accomplish this (that makes use of the <code>sizes</code> prop of next/image),<br>but I add the intended image width and height to the image URL as query parameters.<br>This allows me to get the width and height from the URL and pass it to next/image.</p>
<pre><code class="language-tsx">// app/(subpages)/blog/[slug]/components/mdx-image.tsx
import NextImage from &#39;next/image&#39;

export function MDXImage({
  src,
  alt,
}: React.DetailedHTMLProps&lt;
  React.ImgHTMLAttributes&lt;HTMLImageElement&gt;,
  HTMLImageElement
&gt; &amp; {
  src: string
  alt: string
}) {
  let widthFromSrc, heightFromSrc
  const url = new URL(src, &#39;https://albert-kovalevskij.com&#39;)
  const widthParam = url.searchParams.get(&#39;w&#39;) || url.searchParams.get(&#39;width&#39;)
  const heightParam =
    url.searchParams.get(&#39;h&#39;) || url.searchParams.get(&#39;height&#39;)
  if (widthParam) {
    widthFromSrc = parseInt(widthParam)
  }
  if (heightParam) {
    heightFromSrc = parseInt(heightParam)
  }

  const imageProps = {
    src,
    alt,
    // tweak these to your liking
    height: heightFromSrc || 450,
    width: widthFromSrc || 550,
  }

  return &lt;NextImage {...imageProps} /&gt;
}
</code></pre>
<pre><code class="language-tsx">// In a Markdown file
![alt text](/image.png?width=500&amp;height=400)
</code></pre>
</details>

<h4 id="syntax-highlighting-with-bright">Syntax highlighting with Bright</h4>
<p>Bright is a new RSC-first syntax highlighter by <a href="https://codehike.org/" target="_blank" rel="noopener noreferrer">code-hike</a>.<br>It performs the highlighting on the server, so only the necessary styles and markup are sent to the client.<br>It also has first-class support for extensions like line numbers, highlighting, or whatever you decide to build.</p>
<p>Install the <code>bright</code> package and use it in your MDX components like so:</p>
<pre><code class="language-tsx">import { Code } from &#39;bright&#39;
export const mdxComponents: MDXComponents = {
  // the `a` and `img` tags from before should remain
  pre: Code,
}
</code></pre>
<p>And that&#39;s all you need for great syntax highlighting.</p>
<p>Now that we have MDX setup and equipped with our components, we can render a post.</p>
<p>First, let&#39;s import the <code>getPost</code> function and the <code>PostBody</code> component we created earlier.</p>
<pre><code class="language-tsx">// app/(subpages)/blog/[slug]/page.tsx
import getPosts from &#39;@lib/get-posts&#39;
import { PostBody } from &#39;@mdx/post-body&#39;
</code></pre>
<p>Now we just... render the component.</p>
<pre><code class="language-tsx">import getPosts, { getPost } from &#39;@lib/get-posts&#39;
import { PostBody } from &#39;@mdx/post-body&#39;
import { notFound } from &#39;next/navigation&#39;

export default async function PostPage({
  params,
}: {
  params: {
    slug: string
  }
}) {
  const post = await getPost(params.slug)
  // notFound is a Next.js utility
  if (!post) return notFound()
  // Pass the post contents to MDX
  return &lt;PostBody&gt;{post?.body}&lt;/PostBody&gt;
}
</code></pre>
<p>We can now render a post; that&#39;s pretty cool. </p>
<p>We can optionally choose to build all of our posts at build time,<br>by adding <code>generateStaticParams</code> to the page:</p>
<pre><code class="language-tsx">export async function generateStaticParams() {
  const posts = await getPosts()
  // The params to pre-render the page with.
  // Without this, the page will be rendered at runtime
  return posts.map((post) =&gt; ({ slug: post.slug }))
}
</code></pre>
<Note>
  If you think it's bad that we call `getPost` _and_ `getPosts()`, remember the
  we wrapped `getPosts` in `cache`. `getPost` just calls
  `getPosts`, so we're not making any unnecessary requests to the filesystem (or
  wherever you're getting your posts from).
</Note>

<h2 id="seo">SEO</h2>
<p>The new Metadata API is fantastic, but it&#39;s also a major work in progress. Be sure to check the docs for the latest updates.</p>
<h3 id="metadata-api">Metadata API</h3>
<p>The new <a href="https://beta.nextjs.org/docs/api-reference/metadata" target="_blank" rel="noopener noreferrer">Metadata API</a> has great documentation, so I won&#39;t go into too much detail here.<br>I define the majority of my layout in the root layout and override it as necessary in the leaf pages.</p>
<p>Here&#39;s what my root layout&#39;s metadata looks like:</p>
<pre><code class="language-tsx">// app/layout.tsx
export const metadata = {
  title: {
    template: &#39;%s | Albert Kovalevskij&#39;,
    default: &#39;Albert Kovalevskij&#39;,
  },
  description: &#39;Full-stack developer.&#39;,
  openGraph: {
    title: &#39;Albert Kovalevskij&#39;,
    description: &#39;Full-stack developer.&#39;,
    url: &#39;https://albert-kovalevskij.com&#39;,
    siteName: &quot;Albert Kovalevskij&#39;s site&quot;,
    locale: &#39;en_US&#39;,
    type: &#39;website&#39;,
    // To use your own endpoint, refer to https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation
    // Note that an official `app/` solution is coming soon.
    images: [
      {
        url: `https://www.albert-kovalevskij.com//api/og?title=${encodeURIComponent(
          &quot;Albert Kovalevskij&#39;s site&quot;
        )}`,
        width: 1200,
        height: 630,
        alt: &#39;&#39;,
      },
    ],
  },
  icons: {
    shortcut: &#39;https://www.albert-kovalevskij.com//favicons/favicon.ico&#39;,
  },
  alternates: {
    types: {
      // See the RSS Feed section for more details
      &#39;application/rss+xml&#39;: &#39;https://www.albert-kovalevskij.com//feed.xml&#39;,
    },
  },
}

export const viewport = {
  themeColor: [
    { media: &#39;(prefers-color-scheme: light)&#39;, color: &#39;#f5f5f5&#39; },
    { media: &#39;(prefers-color-scheme: dark)&#39;, color: &#39;#000&#39; },
  ],
}
</code></pre>
<p>And a pages metadata may look like this:</p>
<pre><code class="language-tsx">// app/(subpages)/about/page.tsx
export const metadata = {
  title: &#39;About&#39;,
  alternates: {
    canonical: &#39;https://www.albert-kovalevskij.com//about&#39;,
  },
}
</code></pre>
<h3 id="sitemap-support-sitemapjs">Sitemap support (<code>sitemap.js</code>)</h3>
<p>See @leeerob&#39;s <a href="https://twitter.com/leeerob/status/1639639575843729409" target="_blank" rel="noopener noreferrer">announcement tweet</a> for more details.</p>
<pre><code class="language-tsx">// app/sitemap.ts
import { getPosts } from &#39;./lib/get-posts&#39;

export default async function sitemap() {
  const posts = await getPosts()
  const blogs = posts.map((post) =&gt; ({
    url: `https://www.albert-kovalevskij.com/blog/${post.slug}`,
    lastModified: new Date(post.lastModified).toISOString().split(&#39;T&#39;)[0],
  }))

  const routes = [&#39;&#39;, &#39;/about&#39;, &#39;/blog&#39;, &#39;/projects&#39;].map((route) =&gt; ({
    url: `https://www.albert-kovalevskij.com${route}`,
    lastModified: new Date().toISOString().split(&#39;T&#39;)[0],
  }))

  return [...routes, ...blogs]
}
</code></pre>
<h3 id="generating-an-rss-feed">Generating an RSS Feed</h3>
<p>While waiting for of an official solution for RSS feeds, I&#39;ve created a custom solution that works well for me.<br>I use the <code>marked</code> library to parse the markdown files and then use the <code>rss</code> library to generate the RSS feed.<br>This means the JSX components for MDX are passed through to the RSS feed,<br>so I just try and ensure the components are legible even when not renderd.</p>
<pre><code class="language-tsx">// scripts/rss.ts
import fs from &#39;fs&#39;
import RSS from &#39;rss&#39;
import path from &#39;path&#39;
import { marked } from &#39;marked&#39;
import matter from &#39;gray-matter&#39;

const posts = fs
  .readdirSync(path.resolve(__dirname, &#39;../posts/&#39;))
  .filter(
    (file) =&gt; path.extname(file) === &#39;.md&#39; || path.extname(file) === &#39;.mdx&#39;
  )
  .map((file) =&gt; {
    const postContent = fs.readFileSync(`./posts/${file}`, &#39;utf8&#39;)
    const { data, content }: { data: any; content: string } =
      matter(postContent)
    return { ...data, body: content }
  })
  .sort((a, b) =&gt; new Date(b.date).getTime() - new Date(a.date).getTime())

const renderer = new marked.Renderer()

renderer.link = (href, _, text) =&gt;
  `&lt;a href=&quot;${href}&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;${text}&lt;/a&gt;`

marked.setOptions({
  gfm: true,
  breaks: true,
  renderer,
})

const renderPost = (md: string) =&gt; marked.parse(md)

const main = () =&gt; {
  const feed = new RSS({
    title: &#39;Albert Kovalevskij&#39;,
    site_url: &#39;https://www.albert-kovalevskij.com&#39;,
    feed_url: &#39;https://www.albert-kovalevskij.com/feed.xml&#39;,
    // image_url: &#39;https://www.albert-kovalevskij.com/og.png&#39;,
    language: &#39;en&#39;,
    description: &quot;Albert Kovalevskij&#39;s blog&quot;,
  })

  posts.forEach((post) =&gt; {
    const url = `https://www.albert-kovalevskij.com/blog/${post.slug}`

    feed.item({
      title: post.title,
      description: renderPost(post.body),
      date: new Date(post?.date),
      author: &#39;Albert Kovalevskij&#39;,
      url,
      guid: url,
    })
  })

  const rss = feed.xml({ indent: true })
  fs.writeFileSync(path.join(__dirname, &#39;../public/feed.xml&#39;), rss)
}

main()
</code></pre>
<h2 id="deployment">Deployment</h2>
<p>I use Vercel for deployments (I may be bias), but you can use any static site provider you want with a setup<br>like this because it supports <a href="https://beta.nextjs.org/docs/configuring/static-export" target="_blank" rel="noopener noreferrer">static export</a>. </p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>I hope this post was helpful to you.<br>As a reminder, you can find the source code for this site <a href="https://github.com/maxleiter/maxleiter.com" target="_blank" rel="noopener noreferrer">here</a>.<br>Please try to not think negatively of me for anything you find (but feel free to offer praise for anything you like).</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/build-a-blog-with-nextjs-13</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/build-a-blog-with-nextjs-13</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 15 Apr 2023 21:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Longest Consecutive Sequence: A Set-Based Approach]]></title>
            <description><![CDATA[<p>The &quot;Longest Consecutive Sequence&quot; problem is an intriguing challenge that involves finding the length of the longest sequence of consecutive numbers in an unsorted array.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Given an unsorted array of integers <code>nums</code>, return the length of the longest consecutive elements sequence. The sequence must be strictly consecutive, and the numbers in the sequence can appear in any order in the array.</p>
<h2 id="example">Example</h2>
<ul>
<li><strong>Input</strong>: <code>nums = [100, 4, 200, 1, 3, 2]</code><br><strong>Output</strong>: <code>4</code><br><strong>Explanation</strong>: The longest consecutive elements sequence is <code>[1, 2, 3, 4]</code>. Therefore, its length is 4.</li>
</ul>
<h2 id="set-based-solution">Set-Based Solution</h2>
<pre><code class="language-javascript">function longestConsecutive(nums) {
    const numSet = new Set(nums);
    let longestStreak = 0;

    for (const num of numSet) {
        if (!numSet.has(num - 1)) {
            let currentNum = num;
            let currentStreak = 1;

            while (numSet.has(currentNum + 1)) {
                currentNum += 1;
                currentStreak += 1;
            }

            longestStreak = Math.max(longestStreak, currentStreak);
        }
    }

    return longestStreak;
}
</code></pre>
<h2 id="breaking-down-the-solution">Breaking Down the Solution</h2>
<hr>
<ul>
<li><p><strong>Create a Set</strong>: Convert the array into a set to allow for O(1) lookups and to eliminate duplicates.</p>
</li>
<li><p><strong>Iterate Through the Set</strong>: For each number, check if it&#39;s the start of a sequence (i.e., <code>num - 1</code> is not in the set).</p>
</li>
<li><p><strong>Expand the Sequence</strong>: If it&#39;s the start, count the length of the consecutive sequence by continuously checking the presence of the next numbers in the set.</p>
</li>
<li><p><strong>Track the Longest Sequence</strong>: Update the longest sequence length found so far.</p>
</li>
</ul>
<h3 id="time-complexity">Time Complexity</h3>
<ol>
<li><p><strong>Creating the Set</strong>: Converting the array into a set has a time complexity of <strong>O(N)</strong>, where N is the number of elements in the array. This is because each element is added to the set once.</p>
</li>
<li><p><strong>Iterating Through the Set</strong>: The main loop iterates through each element of the set. For each element, it checks whether it is the start of a new sequence (i.e., whether <code>num - 1</code> is not in the set).</p>
</li>
<li><p><strong>Finding Consecutive Numbers</strong>: For each starting element of a sequence, the algorithm potentially iterates through the consecutive numbers following it. In the worst case, if there is a long consecutive sequence, this could seem like an additional nested loop. However, each element in the array is visited at most twice in these operations: once when it&#39;s checked as a potential start of a sequence, and once when it&#39;s counted as part of an existing sequence.</p>
<p>The key insight is that, although there&#39;s a nested loop, each element from the original array contributes to the longest streak only once. This means the total number of operations is still proportional to N.</p>
</li>
</ol>
<p>Putting it all together, the worst-case time complexity is <strong>O(N)</strong>.</p>
<h3 id="space-complexity">Space Complexity</h3>
<p>The space complexity is primarily determined by the set used to store the elements of the array. Since the set contains every distinct element from the original array, the space complexity is <strong>O(N)</strong>.</p>
<h3 id="summary">Summary</h3>
<p>The set-based approach for the &quot;Longest Consecutive Sequence&quot; problem is efficient with a linear time complexity of O(N) and a linear space complexity of O(N), making it a suitable solution for large arrays.</p>
<h2 id="conclusion">Conclusion</h2>
<hr>
<p>The Longest Consecutive Sequence problem is an excellent application of sets in algorithms, demonstrating their utility in efficiently solving problems that involve uniqueness and ordering. It emphasizes the importance of choosing the right data structure for optimal performance in solving complex problems.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/solving-longest-consecutive-sequence</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/solving-longest-consecutive-sequence</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sat, 31 Dec 2022 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to start contributing to open-source projects]]></title>
            <description><![CDATA[<p>One of the most common questions I&#39;m asked by my computer science friends and students is how they can contribute to an open-source project. In order for me to organize and share my thoughts I thought I&#39;d write something here.</p>
<p>First off, it&#39;s a good idea! Contributing to projects is a fantastic way to build experience, connections, and improve a piece of software you use or rely on. I&#39;ve grown immensely through maintaining my few projects and contributing to a hand full of others. I&#39;ve gained experience in community management, team communication, code review, dependency management, and the list goes on. This post is focused on programming, but don&#39;t forget that issue management, documentation, user support, and bug reporting are all valuable ways you can contribute. </p>
<p>That point about using open-source software is important. The first thing I tell my friends is they should first ensure they&#39;re using some before they attempt to contribute. There are few things that are more satisfying than fixing a bug that&#39;s been bugging you in a program written by someone else, and the motivation that provides is not inconsequential[^1]. As a maintainer, contributor, and extensive procrastinator I&#39;ve seen and felt lack of motivation and burn-out from multiple perspectives, and know how daunting making a contribution can be. So to give you some ideas, here are some applications I use that you may want to try using (or may already use!), and a checklist for how to get started contributing to them:</p>
<ul>
<li><a href="https://www.mozilla.org/en-US/firefox/new/" target="_blank" rel="noopener noreferrer">Firefox</a> (really, it&#39;s <a href="https://arewefastyet.com/mac/benchmarks/overview?numDays=365" target="_blank" rel="noopener noreferrer">(in some cases)</a> as fast as Chrome now! Plus it helps you escape <em>the Alphabet</em>.)</li>
<li><a href="https://www.gimp.org/" target="_blank" rel="noopener noreferrer">GIMP</a> (GNU Image Manipulator Program, a free version of Photoshop.)</li>
<li><a href="https://github.com/microsoft/vscode" target="_blank" rel="noopener noreferrer">VS Code</a> (note that most of it is open-souce, but parts are not.)<ul>
<li>See <a href="https://github.com/VSCodium/vscodium" target="_blank" rel="noopener noreferrer">VSCodium</a> if you want a VS Code fork without Microsoft telemetry and licensing</li>
</ul>
</li>
</ul>
<p>And loads more. I didn&#39;t even mention the vast number of open-source software libraries and frameworks you likely already use. Maybe <a href="https://nextjs.org" target="_blank" rel="noopener noreferrer">Next.js</a>, <a href="https://vuejs.org" target="_blank" rel="noopener noreferrer">Vue</a>, or <a href="https://github.com/pallets/flask" target="_blank" rel="noopener noreferrer">Flask</a> are of interest to you, just to provide a few examples. And below is my framework for getting started.</p>
<h3 id="the-steps">The steps</h3>
<ol>
<li><strong>Find a project and feature or bug to work on</strong>: find one from experience or on their issue tracker/mailing list. Targeting a bug that bothers you or a feature you personally want is ideal due to the motivation aspect mentioned above. If the project is on GitHub these may be in the Milestone or Discussion pages. <a href="https://github.com/explore" target="_blank" rel="noopener noreferrer">GitHub Explore</a> filtered to languages you know or are interested in learning is a great place to start.</li>
<li><strong>Search for prior work or discussions</strong>: it&#39;s important your changes align with the maintainers vision, and you should double check that no one else is working on it. If they are or previously have, you can offer to team-up or ask for their advice.</li>
<li><strong>Familiarize yourself with the code base</strong>: depending on the size, it may not be feasible or sensible for you to grok the entire code base. Instead, try to learn just the parts you need. Feel free to ask the maintainers after searching the documentation and using the below tips if you need help:<ul>
<li>Read the README and CONTRIBUTING files, if they both exist[^2]</li>
<li>Use a package explorer or the Unix <code>find</code> utility to find directories and files of interest</li>
<li>Use <code>git grep</code> to find identifiable or interesting messages/logs/strings in the code (an error alert&#39;s text, for example)</li>
<li>Use <code>git log</code> to explore commits</li>
<li>Use <code>git blame</code> to find out who to email or contact with questions<ul>
<li>You can also check the README or look for a COMMUNITY file to find where to ask</li>
</ul>
</li>
</ul>
</li>
<li><strong>Get crackin&#39;</strong>: Work on the task, reaching out to the maintainers and/or community for help if necessary. Always be courteous, patient, and as clear as possible. Code samples and reproducible cases are king.</li>
<li><strong>Submit your work</strong>: Most likely, submitting your completed work will be done via a mailing list or over a code forge like GitHub and BitBucket. Refer to their documentation and the project&#39;s documentation to determine how to submit your changes. </li>
<li><strong>Wait, Fix, Repeat</strong>: It&#39;s likely you&#39;ll need to address some comments and make some changes to your initial work. That&#39;s okay! Address their comments and send it back to them. Few things feel worse than wasting a reviewers time (especially a volunteer like in many open-source projects), so be sure you self-review your code like you (hopefully) would an English paper.[^3]</li>
</ol>
<h3 id="a-quick-example">A quick example:</h3>
<p>...which you can read more about in <a href="/blog/MSHW0184" target="_blank" rel="noopener noreferrer">my dedicated post</a>.</p>
<ol>
<li>I wanted ambient light support on my Surface Pro 3 running Linux</li>
<li>I searched Google for information and luckily found <a href="https://github.com/linux-surface/linux-surface/issues/121#issue-580967766" target="_blank" rel="noopener noreferrer">this issue and repo</a>:<br><img src="/blog/foss/github-issue.jpg" alt="Image of the linked github issue"></li>
<li>I searched the <abbr title="Linux Kernel Mailing List">LKML</abbr> for previous examples of minor driver adjustments and joined the #linux-surface IRC channel to talk with the other contributors to hear their ideas. </li>
<li>After a few hours and with some help from IRC I determined how to have the device registered using the existing driver and pushed my code to GitHub.</li>
<li>Once the code was reviewed by a few members of linux-surface I submit my patch set to LKML.</li>
<li>It was released in Linux 5.11 🎉</li>
</ol>
<h3 id="in-short">In short</h3>
<ul>
<li>Read the documentation</li>
<li>Find an interesting problem to tackle that motivates you</li>
<li>Discover and grow comfortable with your tools for grepping and exploring unfamiliar code bases </li>
<li>Don&#39;t be afraid to reach out to the maintainers and community; develop communication skills</li>
</ul>
<p>[^1]: One of the few better feelings is fixing a bug in software you made that someone else reported.<br>[^2]: If the README does not exist, consider that a red flag. If the CONTRIBUTING file does not exist, consider asking the maintainers if you could help draft one.<br>[^3]: If you haven&#39;t worked professionally in CS yet, this is likely your first code review, and they&#39;re highly prevalent in the industry, so try extra hard to learn from your mistakes and take note of what you like and dislike about the review left for you.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/contributing-to-oss</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/contributing-to-oss</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Mon, 24 Jan 2022 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Creeper Host API wrapper in TypeScript]]></title>
            <description><![CDATA[<p>I&#39;ve had a server on <a href="https://creeper.host" target="_blank" rel="noopener noreferrer">Creeper Host</a> for around eight years now, and have used it for small side projects and hackathons. Lately, I&#39;ve been trying to  automate more of my life and discovered that the API their in-house control panel uses is <a href="https://creeperhost.docs.apiary.io/" target="_blank" rel="noopener noreferrer">available for general use</a>. I&#39;m making this post in case someone else ever wants to interact with their API via JavaScript. Maybe someday I&#39;ll create a proper repository, but for now my wrapper is incomplete and it&#39;s easier to just include here. It was also a good chance to write some TypeScript from scratch, something I haven&#39;t had the opportunty to do very much of.</p>
<p>To get started, you&#39;ll need to generate a Developer Token on the <a href="https://creeperpanel.com" target="_blank" rel="noopener noreferrer">control panel</a>. Navigate to the <code>Sub-accounts</code> page and generate a new API key at the bottom of the page:</p>
<p><img src="/blog/creeperhost/apiKey.png" alt="Screenshot of the Creeper Host control panel with a blue &#39;Generate Key&#39; button"></p>
<p>Also, install <a href="https://axios-http.com/" target="_blank" rel="noopener noreferrer">axios</a> (or change the below code to your favorite request library, I don&#39;t care):</p>
<pre><code class="language-bash">    yarn add axios
</code></pre>
<p>Then, incorporate these two files:</p>
<pre><code class="language-typescript">import axios, { AxiosRequestConfig } from &quot;axios&quot;;
import { InitializationOptions, MetricResponse, RestartResponse } from &quot;./types&quot;;

export default class Client {
    private instance: string;
    constructor({ apiKey, apiSecret, apiUrl = &#39;https://api.creeper.host&#39;, instanceId}: InitializationOptions) {
        axios.defaults.baseURL = apiUrl;

        axios.defaults.headers.common[&#39;key&#39;] = apiKey;
        axios.defaults.headers.common[&#39;secret&#39;] = apiSecret;
        axios.defaults.headers.common[&#39;Content-Type&#39;] = &#39;application/json&#39;;

        this.instance = instanceId;
    }

    private async request&lt;T = any&gt;({ method = &quot;GET&quot;, apiRoute, body }: { method: &quot;GET&quot; | &quot;POST&quot;, apiRoute: string, body?: any}) {
        const config: AxiosRequestConfig = {
            method,
            url: apiRoute,
            data: body
        }

        console.log(`[${method}] ${apiRoute}`, body ? `\t ${JSON.stringify(body)}` : &#39;&#39;);

        const request = await axios.request&lt;T&gt;(config);
        return request.data;
    }

    public os = {
            getram: async () =&gt; {
                return this.request&lt;MetricResponse&gt;({ method: &quot;GET&quot;, apiRoute: &quot;os/getram&quot; });
            },
            getssd: async () =&gt; {
                return this.request&lt;MetricResponse&gt;({ method: &quot;GET&quot;, apiRoute: &quot;os/getssd&quot; });
            },
    }

    public minecraft = {
        restartserver: async () =&gt; {
            return this.request&lt;RestartResponse&gt;({ method: &quot;POST&quot;, apiRoute: &quot;minecraft/restartserver&quot;, body: { instance: this.instance} });
        },
    }
}
</code></pre>
<pre><code class="language-typescript">export type MetricResponse = {
    status: &#39;success&#39;;
    free: number;
    used: number;
} | {
    status: &#39;error&#39;,
    message: string
}

export type RestartResponse = {
    status: &#39;success&#39;;
    message: string;
} | {
    status: &#39;error&#39;,
    message: string
}
</code></pre>
<p>Finally, create an instance via <code>new Client({ apiKey, apiSecret, instanceId });</code><br>You can use it by finding what you want to call on the Creeper Host docs and accessing that on the client; I purposefully used the same naming scheme. For example,</p>
<pre><code class="language-typescript">Client.os.getram(): Promise&lt;MetricResponse&gt;
</code></pre>
<p>corresponds to the <a href="https://creeperhost.docs.apiary.io/#/reference/0/server/get-server-ram-details/200?mc=reference%2F0%2Fserver%2Fget-server-ram-details%2F200" target="_blank" rel="noopener noreferrer">https://api.creeper.host/os/getram</a> endpoint.</p>
<p>I removed some methods from the above to avoid cluttering this page, but it&#39;s straight forward to add your own. If you really want to use this, contact me and I can set up a repo for us to collaborate. Also, if you have suggestions on how I can improve this, let me know via <a href="mailto:kovalevskij.albert@gmail.com" target="_blank" rel="noopener noreferrer">email</a> or on <a href="https://twitter.com/AlbertKovalevsk" target="_blank" rel="noopener noreferrer">Twitter</a>.</p>
]]></description>
            <link>https://albert-kovalevskij.com/private/blind75/creeperhost-api</link>
            <guid isPermaLink="false">https://albert-kovalevskij.com/private/blind75/creeperhost-api</guid>
            <dc:creator><![CDATA[Albert Kovalevskij]]></dc:creator>
            <pubDate>Sun, 21 Nov 2021 22:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>