Skip to the notes
JSGroundwork
JSGroundwork handwritten · web dev
✎Playground→⌘Problems↻Review🔥Progress

Chapters

34 chapters
⌕
Beginner10›
B1Complexity analysisB2Arrays & stringsB3HashingB4Two pointersB5Sliding windowB6Binary searchB7Sorting algorithmsB8Stacks & queuesB9Linked listsB10Basic recursion
Intermediate12›
I1TreesI2Tree problems in depthI3Heaps & priority queuesI4Graphs: representationI5Graph problemsI6BacktrackingI7DP: 1DI8DP: 2DI9Greedy algorithmsI10IntervalsI11Bit manipulationI12Matrix problems
Advanced12›
A1Advanced DPA2Union-FindA3Advanced graph algorithmsA4Minimum Spanning TreeA5TriesA6Segment & Fenwick treesA7String algorithmsA8Monotonic stack & queueA9Design problemsA10Advanced backtrackingA11Topological patternsA12Interview strategy
/ search[ ] chaptert top

DSA in JS levels

1Beginner2Intermediate3Advanced

Ready to read

JSJavaScript⑂Git◎Interview prepΣDSA in JSSDSystem Design
More topics15›
</>HTML{ }CSS⚛ReactNNext.jsNeNest.jsTSTypeScriptNoNode.js🐳DockerDBSQL & Databases✓Testing🔒Web Security☁Cloud & DevOps◈GraphQL◆Redis☸Kubernetes
100%
B6

Binary search

Halving the search space is the single highest-leverage trick in DSA.

The core idea

Binary search needs exactly one property from the search space: at every point, you can tell which half the answer is in without checking it directly. On a sorted array that's obvious — but the same idea applies to any "monotonic" space, which is why binary search shows up far more often than "is this array sorted" questions alone would suggest.

1 3 6 9 12 15 20 mid target = 15 > 9 → whole left half (1,3,6,9) is eliminated, no need to check any of it n → n/2 → n/4 → n/8 → … → 1 log₂(n) halvings until one element remains — that's the O(log n)
Each comparison eliminates half the remaining space, not just one element.

The template that avoids off-by-one bugs

function binarySearch(sorted, target) {
  let lo = 0, hi = sorted.length - 1;
  while (lo <= hi) {              // note: <=, not <
    const mid = lo + Math.floor((hi - lo) / 2); // avoids overflow, same as (lo+hi)>>1 in JS
    if (sorted[mid] === target) return mid;
    if (sorted[mid] < target) lo = mid + 1;
    else hi = mid - 1;
  }
  return -1; // not found
}
⚠ The two bugs that show up every time
  • lo <= hi vs lo < hi — get this wrong and you'll either miss the last candidate or loop forever.
  • mid = (lo + hi) / 2 can integer-overflow in other languages (not JS, but say it right anyway) — the lo + (hi - lo) / 2 form is the safe habit.

Watch the search space halve, step by step

sorted = [1, 3, 6, 9, 12, 15, 20], target = 15:

steplohimid (value)compareaction
1063 (9)9 < 15lo = 4
2465 (15)matchreturn 5

Seven elements, but only two comparisons — log₂(7) ≈ 2.8, rounded up to 3 worst-case steps. Compare that to a linear scan, which could need all 7. At n = 1,000,000, binary search needs about 20 steps; a linear scan could need a million.

Binary search on the answer, not the array

This is the pattern that separates candidates who've memorized one template from candidates who understand the idea. Whenever a problem asks for the minimum value that satisfies a condition (or maximum), and "does value X work?" gets easier to check as X changes monotonically, you can binary search over the range of possible answers instead of the input array.

// minimum "speed" to eat all bananas within h hours — classic answer-space search
function minEatingSpeed(piles, h) {
  function hoursNeeded(speed) {
    let hours = 0;
    for (const pile of piles) hours += Math.ceil(pile / speed);
    return hours;
  }

  let lo = 1, hi = Math.max(...piles);
  while (lo < hi) {
    const mid = lo + Math.floor((hi - lo) / 2);
    if (hoursNeeded(mid) <= h) hi = mid;   // mid works — answer could be smaller
    else lo = mid + 1;                     // mid too slow — need bigger speed
  }
  return lo;
}

The array here isn't even sorted — what's monotonic is the relationship between speed and hours needed: faster speed always means fewer or equal hours. That monotonic relationship is the real requirement for binary search, not "is the input array sorted."

Finding a boundary (first/last occurrence)

// leftmost index where nums[i] >= target — the building block for
   "find first occurrence" and most boundary-search variants
function lowerBound(nums, target) {
  let lo = 0, hi = nums.length; // note: hi = length, not length-1, here
  while (lo < hi) {
    const mid = lo + Math.floor((hi - lo) / 2);
    if (nums[mid] < target) lo = mid + 1;
    else hi = mid;
  }
  return lo;
}
Say it like this → "Even though the array isn't sorted, the answer space is monotonic — if speed X works, every speed faster than X also works — so I can binary search over the range of possible speeds instead of scanning them all."

See the range collapse

Watch the live range collapse. Ten candidates become one in four comparisons — and the count of comparisons is just how many times you can halve the array.

Binary search — halving the search space
Live range

Recognizing it in an unseen problem

  • Data is sorted, or the answer space is monotonic ("if X works, does X+1 also work?")
  • The prompt says "minimum/maximum value such that…"
  • A brute force would try every candidate linearly — O(n) or O(n·check)
  • You can write a fast "does this candidate work?" check — that check becomes the comparison inside the binary search
Practice this layer

Opens in the editor — write it, run it, and check it against real tests.

Binary Search5 tests · beginnerSearch Insert Position5 tests · beginnerSearch a 2D Matrix4 tests · intermediateFirst and Last Position of a Value5 tests · intermediateSearch in Rotated Sorted Array4 tests · intermediateSearch in Rotated Sorted Array II4 tests · advancedFind Minimum in Rotated Sorted Array4 tests · intermediateFind Peak Element5 tests · intermediateKoko Eating Bananas5 tests · advancedCapacity to Ship Packages Within D Days5 tests · advancedSplit Array Largest Sum5 tests · advancedMedian of Two Sorted Arrays5 tests · advancedInteger Square Root4 tests · beginnerValid Perfect Square4 tests · beginnerFind the Duplicate Number5 tests · advanced
←previousSliding window↑ CovernextSorting algorithms→