Introduction
Binary Search is one of the most fundamental and efficient algorithms in computer science. It’s a divide-and-conquer algorithm that searches for a target value in a sorted array by repeatedly dividing the search space in half. With a time complexity of O(log n), it’s significantly faster than linear search for large datasets.
In this article, we’ll explore Binary Search concepts through practical LeetCode problems, providing clean, well-explained solutions in both C# and Python.
What is Binary Search?
Binary Search is an algorithm that finds the position of a target value within a sorted array by:
- Comparing the target with the middle element
- If they match, return the position
- If target is smaller, search the left half
- If target is larger, search the right half
- Repeat until found or search space is exhausted
Key Requirements:
- Sorted Array: The array must be sorted (ascending or descending)
- Random Access: Must be able to access elements by index
- Comparable Elements: Elements must be comparable
Time Complexity:
- Best Case: O(1) – target is at the middle
- Average Case: O(log n) – target is found after log₂(n) comparisons
- Worst Case: O(log n) – target is at the edge or not found
Space Complexity:
- Iterative: O(1) – only using a few variables
- Recursive: O(log n) – recursion stack depth
Binary Search Template
The standard binary search template uses three pointers:
left: Left boundary of search spaceright: Right boundary of search spacemid: Middle element
int left = 0, right = nums.Length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1; // Not found
Important: Use left + (right - left) / 2 instead of (left + right) / 2 to avoid integer overflow.
Problem 1: Search Insert Position
Problem Statement
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
Examples
Input: nums = [1,3,5,6], target = 5
Output: 2
Input: nums = [1,3,5,6], target = 2
Output: 1
Input: nums = [1,3,5,6], target = 7
Output: 4
Understanding the Problem
We need to find the insertion position for a target in a sorted array. This is essentially finding the leftmost position where we can insert the target while maintaining sorted order.
Solution Strategy
Modified Binary Search:
- Use binary search to find the position
- If
nums[mid] >= target, the insertion point is atmidor to the left - If
nums[mid] < target, the insertion point is to the right - When
left == right, we’ve found the insertion position
C# Solution
public class Solution
{
public int SearchInsert(int[] nums, int target)
{
// Binary search with O(log n) complexity
int left = 0, right = nums.Length;
while (left < right)
{
// Calculate middle to avoid overflow
int mid = left + (right - left) / 2;
if (nums[mid] >= target)
{
// Target is at mid or to the left
right = mid;
}
else
{
// Target is to the right
left = mid + 1;
}
}
return left;
}
}
Python 3 Solution
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while left < right:
middle = left + (right - left) // 2
if nums[middle] >= target:
right = middle
else:
left = middle + 1
return left
Complexity Analysis
- Time Complexity: O(log n) where n is the length of nums
- Space Complexity: O(1)
Problem 2: Find Minimum in Rotated Sorted Array
Problem Statement
Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:
[4,5,6,7,0,1,2]if it was rotated 4 times[0,1,2,4,5,6,7]if it was rotated 7 times
Given the sorted rotated array nums of unique elements, return the minimum element of this array.
You must write an algorithm that runs in O(log n) time.
Example
Input: nums = [3,4,5,1,2]
Output: 1
Explanation: The original array was [1,2,3,4,5] rotated 3 times.
Understanding the Problem
In a rotated sorted array, there’s a pivot point where the array was rotated. The minimum element is at this pivot. The array has two sorted portions, and we need to find where the rotation occurred.
Solution Strategy
Binary Search for Pivot:
- Compare
nums[mid]withnums[right] - If
nums[mid] > nums[right], the pivot is in the right half (including mid) - If
nums[mid] <= nums[right], the pivot is in the left half (including mid) - When
left == right, we’ve found the minimum
C# Solution
public class Solution
{
public int FindMin(int[] nums)
{
int left = 0, right = nums.Length - 1;
while (left < right)
{
int mid = left + (right - left) / 2;
// If middle is greater than right, pivot is in right half
if (nums[mid] > nums[right])
{
left = mid + 1;
}
else
{
// Pivot is in left half (including mid)
right = mid;
}
}
return nums[left];
}
}
Python 3 Solution
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums) - 1
while left < right:
middle = left + (right - left) // 2
if nums[middle] > nums[right]:
left = middle + 1
else:
right = middle
return nums[left]
Complexity Analysis
- Time Complexity: O(log n) where n is the length of nums
- Space Complexity: O(1)
Problem 3: Search in Rotated Sorted Array
Problem Statement
There is an integer array nums sorted in ascending order (with distinct values).
Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed).
Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.
You must write an algorithm with O(log n) runtime complexity.
Example
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Understanding the Problem
We need to search for a target in a rotated sorted array. The challenge is determining which half of the array to search, since the array is rotated.
Solution Strategy
Binary Search with Rotation Handling:
- Determine which half is sorted by comparing
nums[mid]withnums[right] - If left half is sorted:
- If target is in range
[nums[left], nums[mid]], search left - Otherwise, search right
- If target is in range
- If right half is sorted:
- If target is in range
[nums[mid], nums[right]], search right - Otherwise, search left
- If target is in range
C# Solution
public class Solution
{
public int Search(int[] nums, int target)
{
int left = 0, right = nums.Length - 1;
while (left < right)
{
int mid = left + (right - left) / 2;
// Determine which half is sorted
if (nums[mid] > nums[right])
{
// Left half is sorted
if (target > nums[mid] || target <= nums[right])
{
// Target is in right half
left = mid + 1;
}
else
{
// Target is in left half
right = mid;
}
}
else
{
// Right half is sorted
if (target > nums[mid] && target <= nums[right])
{
// Target is in right half
left = mid + 1;
}
else
{
// Target is in left half
right = mid;
}
}
}
// Check if target was found
if (left == right && nums[left] == target)
return left;
return -1;
}
}
Python 3 Solution
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums) - 1
while left < right:
middle = left + (right - left) // 2
if nums[middle] > nums[right]:
# Left half is sorted
if target > nums[middle] or target <= nums[right]:
left = middle + 1
else:
right = middle
else:
# Right half is sorted
if target > nums[middle] and target <= nums[right]:
left = middle + 1
else:
right = middle
if left == right and nums[left] == target:
return left
return -1
Complexity Analysis
- Time Complexity: O(log n) where n is the length of nums
- Space Complexity: O(1)
Problem 4: Capacity To Ship Packages Within D Days
Problem Statement
A conveyor belt has packages that must be shipped from one port to another within days days.
The ith package on the conveyor belt has a weight of weights[i]. Each day, we load the ship with packages on the conveyor belt (in the order given by weights). We may not load more weight than the maximum weight capacity of the ship.
Return the least weight capacity of the ship that will result in all the packages on the conveyor belt being shipped within days days.
Example
Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5
Output: 15
Explanation: A ship capacity of 15 is the minimum to ship all the packages in 5 days like this:
1st day: 1, 2, 3, 4, 5
2nd day: 6, 7
3rd day: 8
4th day: 9
5th day: 10
Understanding the Problem
This is a binary search on answer problem. We’re not searching for an element in an array, but searching for the minimum capacity that satisfies the constraint.
Solution Strategy
Binary Search on Answer:
- Search Space: Minimum capacity is
max(weights)(must carry heaviest package), maximum issum(weights)(carry all in one day) - Validation Function: For a given capacity, simulate loading packages and count days needed
- Binary Search: If days needed >
days, increase capacity; otherwise, try smaller capacity - Return the minimum valid capacity
C# Solution
public class Solution
{
public int ShipWithinDays(int[] weights, int days)
{
// Minimum capacity: must carry heaviest package
int left = weights.Max();
// Maximum capacity: carry all packages in one day
int right = weights.Sum();
while (left < right)
{
int mid = left + (right - left) / 2;
// Simulate loading with current capacity
int currentCapacity = 0;
int shipsNeeded = 1;
foreach (int weight in weights)
{
currentCapacity += weight;
// If exceeds capacity, need another ship
if (currentCapacity > mid)
{
currentCapacity = weight;
shipsNeeded++;
}
}
// If we need more ships than available days, increase capacity
if (shipsNeeded > days)
{
left = mid + 1;
}
else
{
// Try smaller capacity
right = mid;
}
}
return left;
}
}
Python 3 Solution
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
left = max(weights)
right = sum(weights)
while left < right:
middle = left + (right - left) // 2
currentCapacity = 0
shipsNeeded = 1
for weight in weights:
currentCapacity += weight
if currentCapacity > middle:
currentCapacity = weight
shipsNeeded += 1
if shipsNeeded > days:
left = middle + 1
else:
right = middle
return left
Complexity Analysis
- Time Complexity: O(n × log(sum(weights))) where n is the number of packages
- Binary search: O(log(sum(weights)))
- Validation: O(n) for each search
- Space Complexity: O(1)
Key Takeaways
Binary Search Patterns:
1. Standard Binary Search
- Search for exact target in sorted array
- Template:
left <= right, return index or -1
2. Binary Search for Insertion Position
- Find where to insert element
- Template:
left < right, returnleft
3. Binary Search on Rotated Array
- Handle rotation by comparing with boundaries
- Determine which half is sorted first
4. Binary Search on Answer
- Search for optimal value that satisfies condition
- Requires validation function
- Common in optimization problems
Common Binary Search Techniques:
Avoiding Integer Overflow:
int mid = left + (right - left) / 2; // ✅ Correct
int mid = (left + right) / 2; // ❌ May overflow
Boundary Conditions:
left <= right: Inclusive boundaries, standard searchleft < right: Exclusive right boundary, insertion positionright = midvsright = mid - 1: Depends on problem
Search Space Reduction:
- Always eliminate at least one element per iteration
- Ensure search space shrinks:
left = mid + 1orright = mid - 1
When to Use Binary Search:
- Sorted Array: Array must be sorted (or can be sorted)
- Search Problem: Finding element, position, or optimal value
- Optimization: Finding minimum/maximum that satisfies condition
- O(log n) Requirement: When O(log n) time complexity is needed
Problem-Solving Steps:
- Identify Search Space: What are we searching for? (element, position, value)
- Define Boundaries: What are the min and max possible values?
- Write Validation: How do we check if a value is valid? (for binary search on answer)
- Choose Template: Standard search, insertion, or rotated array?
- Handle Edge Cases: Empty array, single element, not found
Common Mistakes:
- Integer Overflow: Using
(left + right) / 2instead ofleft + (right - left) / 2 - Infinite Loop: Not updating boundaries correctly
- Off-by-One Errors: Wrong boundary conditions
- Missing Edge Cases: Not handling empty arrays or single elements
Conclusion
Binary Search is a powerful algorithm that provides O(log n) time complexity for search problems. The key is recognizing when a problem can be solved with binary search and choosing the right template.
Key patterns to remember:
- Standard Search: Find exact element in sorted array
- Insertion Position: Find where to insert element
- Rotated Array: Handle rotation by comparing with boundaries
- Search on Answer: Find optimal value that satisfies condition
Practice identifying binary search opportunities and mastering the different templates. The more you practice, the better you’ll become at recognizing when and how to apply binary search.
Remember: Binary search requires a sorted array (or sortable problem space) and works by repeatedly dividing the search space in half. Always ensure your boundaries are updated correctly to avoid infinite loops.
Happy coding!
