Skip to main content

Command Palette

Search for a command to run...

Algorithms

Algorithms for interviews

Updated
6 min readView as Markdown
Algorithms
V

Sky always blue

Control flow for algorithm

Use caseUse this
Exit only the loop? Bonus → only the most inner loopbreak
Skip this iteration and continue loop?continue
Exit function early?return

Use-case of break

  include(substring) {
        const str = this.value;
        const n = str.length;
        const m = substring.length;

        if(m === 0) return true;
        if(m > n) return false;
        for(let i=0; i <= n - m ; i++) {
            let matches = true;
            for(let j=0;j < m;j++) {
                if(str[i+j]!== substring[j]) {
                    matches = false;
                    break;
                }
            }
            if(matches) return true;
        }
        return false;
    }


    //stream API in java
    *[Symbol.iterator]() {
        for(let val of this.source) {
            let include = true;
            let result = val;
            for(let operation of this.operations) {
                if(operation.type === 'map') {
                    result = operation.cb(val);
                }
                if(operation.type === 'filter' && !operation.cb(val)) {
                    include = false; //stop applying further operations to this value (because one filter already rejected it).
                }
            }
            if (include) yield result;
        }
    }

For of vs let i


🔁 for...of — When you care about values

✅ Use this when:

  • You only need the item itself (not the index).

  • You're looping through strings or arrays.

  • You don’t need to modify the original array (for strings, you can’t anyway—they're immutable).

📌 Example:

class Trie {
  insert(text) {
      let node = this.root;
      for(let char of text) {
           if(!node.children[char]) {
               node.children[char] = new TrieNode();
            }
            node = node.children[char];
      }
      node.isEndOfWord = true;
  }
}

🔁 for (let i = 0; i < ...) — When you need indexes

jsCopyEditfor (let i = 0; i < arr.length; i++) {
    // use i and/or arr[i]
}

✅ Use this when:

  • You need the index (to track positions, or access neighbors).

  • You plan to modify the array.

  • You want to loop over part of the array or string (e.g., starting in the middle).

  • You might need to look ahead or behind in the sequence.

📌 Example:

jsCopyEditlet arr = ['a', 'b', 'c'];
for (let i = 0; i < arr.length; i++) {
    if (i % 2 === 0) {
        console.log(arr[i]); // a, c
    }
}
Use CaseUse for...ofUse for (let i = 0; ...)
Need just the value✅ but overkill
Need the index
Need to modify elements❌ (can’t with strings)
Need to skip or jump steps
Looping over object properties❌ (use for...in or Object.keys)

Running time

Sort (array data structure)

💡
All of these sorts are based on index key(number) to swap values

Base-case for these smart sort-algorithm ?

Devide and conquer technical

  • Binary search arr ( when left >= right => can’t find the value)

  • QuickSort ( when left >= right => can’t partition anymore)

  • MergeSort ( when arr.length === 0 => can’t devide the value anymore)

Binary search array

Mergesort

Quicksort

Recursive

Recap

• Recursion is when a function calls itself.

• Every recursive function has two cases: the base case

and the recursive case.

• A stack has two operations: push and pop.

• All function calls go onto the call stack.

• The call stack can get very large, which takes up a lot of memory.

🌳 Why Recursion Fits Trees Perfectly

1. Trees Are Naturally Recursive Structures

A tree is defined in terms of smaller trees:

textCopyEditTree:
- A node (with data)
- Zero or more child trees

So a tree is self-similar — the same structure repeats within itself, just smaller. This is exactly what recursion is great at!


2. Recursion Mirrors Tree Traversal

To traverse a tree, you typically:

  • Do something at the current node

  • Then recursively do the same thing to each child node

Example in JavaScript (pre-order traversal):

jsCopyEditfunction traverse(node) {
  console.log(node.value); // Visit current node

  for (let child of node.children) {
    traverse(child); // Visit child recursively
  }
}

This "call itself on smaller parts" is exactly how recursion works.


3. Call Stack = Implicit Tree Path

When recursion goes deep:

  • Each function call remembers "where it came from"

  • That’s like walking down a branch in the tree

  • When you return (go back up), you unwind the tree path

The function stack follows the shape of the tree path!


4. Cleaner and Simpler Code

Without recursion, tree algorithms are harder to write. Compare:

With recursion:

jsCopyEditfunction sumTree(node) {
  if (!node) return 0;
  return node.value + sumTree(node.left) + sumTree(node.right);
}

Without recursion (iterative with stack):

jsCopyEditfunction sumTreeIterative(root) {
  if (!root) return 0;
  let stack = [root], sum = 0;

  while (stack.length) {
    let node = stack.pop();
    sum += node.value;
    if (node.right) stack.push(node.right);
    if (node.left) stack.push(node.left);
  }

  return sum;
}

Recursion looks more like the structure of the problem.


🧠 Summary

Tree PropertyWhy Recursion Fits
Self-similar structureRecursion breaks problems into parts
Branching pathsRecursive calls explore each branch
Going deep & back upCall stack mirrors tree path
Natural expression of traversalCleaner and intuitive code

If you’re building a decision system, DOM traversal, file structure, AI reasoning, or game trees, recursion is often the most natural fit.

Main Signals for Using Two-Pointer Technique

🔁 1. Comparing or checking elements from both ends

  • You need to compare, reverse, or meet in the middle

  • Keywords: "is it a palindrome?", "reverse", "mirror", "container", "sorted"

Examples:

  • isPalindrome("abba")

  • reverseString(["h", "e", "l", "l", "o"])

  • containerWithMostWater(height)


➕ 2. Finding a pair/triplet that satisfies a condition

  • Usually used in sorted arrays

  • Goal: find two numbers that sum to a target, or find duplicates

Examples:

  • twoSumSorted([2,7,11,15], target = 9)

  • 3Sum, removeDuplicatesSorted


📏 3. Shrinking or sliding a window

  • You're finding substrings, subarrays, or ranges

  • Need to dynamically expand and contract a window of elements

Examples:

  • longestSubstringWithoutRepeatingCharacters("abcabcbb")

  • minWindowSubstring(s, t)

  • maximumSumSubarray


✂️ 4. In-place array manipulation

  • Asked to do something without extra space (i.e., O(1))

  • Remove elements, move items, overwrite data

Examples:

  • removeElement(nums, val)

  • moveZeroes(nums)

  • mergeSortedArraysInPlace


🔀 5. Two sorted arrays or ranges

  • Problems involving merging, intersections, comparisons between two lists

Examples:

  • mergeTwoSortedArrays(a, b)

  • findMedianSortedArrays

  • intersection of two sorted arrays


🧠 Quick Mnemonic:

"Compare ➡️ Slide ➡️ Shrink ➡️ Merge ➡️ Modify"

If you see these verbs or problems that feel like them, two-pointers might be the answer.

Sliding window

Theory

Maximum sum of a contigious subarray of size 3

smallest sub-array with given sum

Backtracking

Combination Sum problem

Letter Combinations of a phone number

Dynamic programming

Best time to buy stock

String

Longest Palindromic Substring

To be updated ....