Given a sorted array, find a target in O(log n) by repeatedly halving the search space. The canonical lo/hitemplate — with its inclusive bounds and overflow-safe midpoint — anchors every binary-search variant you'll ever write.
Given a sorted integer array nums and an integer target, return the index of target if it exists, or -1 if it does not. For example: nums=[-1,0,3,5,9,12], target=9 → the answer is 4 (0-indexed). And nums=[-1,0,3,5,9,12], target=2 → -1 (not present). You may not use any built-in binary search library.
lo = 0, hi = nums.length - 1. Both endpoints are inside the current search window.lo <= hi (not <) so a single-element window is still checked.mid = lo + Math.floor((hi - lo) / 2) instead of (lo + hi) / 2 — avoids integer overflow when lo + hi exceeds 32 bits.nums[mid] === target, return mid. If nums[mid] < target, everything up to and including mid is too small → move lo to mid + 1. Otherwise move hi to mid - 1.lo < hi or lo <= hi? With inclusive bounds (both lo and hi point at valid candidates), use <=. Switching to exclusive hi = nums.length and lo < hi is equally correct but mixes the two styles silently. Pick one template and stick to it.The iterative version uses O(1) extra space — just two integer pointers. A recursive version uses O(log n) stack space. Always prefer iterative unless the problem requires recursion.
lo=0, hi=5. Amber cells are the active window.1function search(nums: number[], target: number): number {2▶ let lo = 0;3▶ let hi = nums.length - 1;45 while (lo <= hi) {6 const mid = lo + Math.floor((hi - lo) / 2); // avoid overflow7 if (nums[mid] === target) return mid;8 if (nums[mid] < target) lo = mid + 1; // target is right9 else hi = mid - 1; // target is left10 }11 return -1; // not found12}
function search(nums: number[], target: number): number {
let lo = 0;
let hi = nums.length - 1;
while (lo <= hi) {
const mid = lo + Math.floor((hi - lo) / 2); // avoid overflow
if (nums[mid] === target) return mid;
if (nums[mid] < target) lo = mid + 1; // target is right
else hi = mid - 1; // target is left
}
return -1; // not found
}lo starts at index 0; hi starts at the last valid index nums.length - 1. Both pointers point at real elements, so the loop condition is <=.lo <= hi ensures we still check the window even when it shrinks to a single element. If we used <we'd miss the final candidate.lo + Math.floor((hi - lo) / 2) is mathematically identical to Math.floor((lo + hi) / 2) but avoids overflow when both pointers are large. This matters in Java/C++; in JS numbers are 64-bit floats, but the idiom is still canonical.lo = mid + 1 (not mid — we already know midisn't the answer); too-large means hi = mid - 1 for the same reason.lo > hi — the window collapsed with no match. Return -1.mid and keep searching rather than returning on match — that pattern is Find First and Last Position (LC 34).function search(nums: number[], target: number): number {
let lo = 0;
let hi = nums.length - 1;
while (lo <= hi) {
const mid = lo + Math.floor((hi - lo) / 2); // avoid overflow
if (nums[mid] === target) return mid;
if (nums[mid] < target) lo = mid + 1; // target is right
else hi = mid - 1; // target is left
}
return -1; // not found
}Ignore that the array is sorted and just walk it left to right, returning the first index whose value equals target— the baseline that works on any array, sorted or not.
function search(nums: number[], target: number): number {
for (let i = 0; i < nums.length; i++) {
if (nums[i] === target) return i;
}
return -1;
}| sorted array, find target | lo/hi binary search template |
| "find first / last position" | binary search + keep going on match |
| "minimize / maximize X such that feasible" | binary search on the answer |
| rotated sorted array | binary search — pick the sorted half |
function search(nums: number[], target: number): number {
let lo = 0, hi = nums.length - 1;
while (lo <= hi) {
const mid = lo + Math.floor((hi - lo) / 2);
if (nums[mid] === target) return mid;
if (nums[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}lo and hi point at real candidates, so a window of size 1 (lo === hi) must still be checked.nums = [-1, 0, 3, 5, 9, 12] and target = 9, what index does the algorithm return?mid = lo + Math.floor((hi - lo) / 2) preferred over Math.floor((lo + hi) / 2)?lo <= hi. What goes wrong if you write lo < hi instead (keeping the same inclusive bounds)?nums[mid] < target, you set: