The Ultimate Guide to Using Binary Search on Rotated and Repeated Arrays !
Binary search is a fundamental algorithmic technique used to efficiently locate elements in a sorted array. It is always used when the array is sorted. But what do you do if there are multiple elements in that array or the array is sorted but rotated on some random pivot ?
1. Searching in a Rotated Sorted Array
The Problem
Imagine you are given a sorted array that has been rotated at an unknown pivot, and you need to find the index of a specific target value. If the target does not exist in the array, the function should return -1
. This problem demands an O(log n)
runtime complexity, suggesting a binary search-based approach.
Understanding the Rotated Array
A rotated sorted array is one where the sorted order has been shifted to the left or right by some pivot. For example, [4, 5, 6, 7, 0, 1, 2]
is a sorted array rotated at pivot 3
.
To solve this, we need to identify which part of the array (left or right of the mid-point) is sorted and decide where to continue the search.
Approach
We can modify the binary search algorithm with the following steps:
Initialize Pointers: Set two pointers,
lo
andhi
, at the start and end of the array, respectively.Binary Search Loop: While
lo
is less than or equal tohi
:Calculate the middle index,
mid
.Check if the middle element
nums[mid]
is the target. If yes, return its index.Determine which part of the array is sorted:
If the left part (
nums[lo]
tonums[mid]
) is sorted:Check if the target lies within this range. If yes, adjust
hi
tomid - 1
.Otherwise, adjust
lo
tomid + 1
to search in the right part.
If the right part (
nums[mid]
tonums[hi]
) is sorted:Check if the target lies within this range. If yes, adjust
lo
tomid + 1
.Otherwise, adjust
hi
tomid - 1
.
Return the Result: If the target is not found, return
-1
.
Code Implementation
class Solution {
public int search(int[] nums, int target) {
int lo = 0;
int hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] == target) {
return mid;
}
// Determine which part is sorted
if (nums[lo] <= nums[mid]) { // Left part is sorted
if (nums[lo] <= target && target < nums[mid]) {
hi = mid - 1; // Target is in the left part
} else {
lo = mid + 1; // Target is in the right part
}
} else { // Right part is sorted
if (nums[mid] < target && target <= nums[hi]) {
lo = mid + 1; // Target is in the right part
} else {
hi = mid - 1; // Target is in the left part
}
}
}
return -1; // Target not found
}
}
Complexity
Time Complexity:
O(log n)
due to the binary search reducing the search space by half each iteration.Space Complexity:
O(1)
since only a few extra variables are used.
2. Finding the Range of a Target in a Sorted Array
The Problem
Given an array of integers nums
sorted in non-decreasing order, find the starting and ending position of a given target value. The challenge here is to efficiently find both occurrences using a modified binary search.
Why Simple Binary Search Isn't Enough
A regular binary search will find an occurrence of the target, but not necessarily its first or last position. To find both, we need to perform two separate binary searches: one to find the first occurrence and another to find the last.
Approach
First Binary Search: To find the last occurrence of the target:
Set
si
(start index) to 0 andei
(end index) tonums.length - 1
.Use a binary search; if
nums[mid]
equals the target, set the result's end index (res[1]
) tomid
and continue searching in the right half.
Second Binary Search: To find the first occurrence of the target:
Reset
si
to 0 andei
tonums.length - 1
.Use a similar binary search; if
nums[mid]
equals the target, set the result's start index (res[0]
) tomid
and continue searching in the left half.
Return the Result: The array
res
contains the starting and ending indices of the target value.
Code Implementation
class Solution {
public int[] searchRange(int[] nums, int target) {
int si = 0, ei = nums.length - 1;
int[] res = {-1, -1}; // Initialize result array
// First binary search to find the last occurrence
while (si <= ei) {
int mid = si + (ei - si) / 2;
if (target < nums[mid]) {
ei = mid - 1;
} else if (target > nums[mid]) {
si = mid + 1;
} else {
res[1] = mid; // Update end index
si = mid + 1; // Continue searching in the right half
}
}
// Reset the pointers for the second binary search
si = 0;
ei = nums.length - 1;
// Second binary search to find the first occurrence
while (si <= ei) {
int mid = si + (ei - si) / 2;
if (target < nums[mid]) {
ei = mid - 1;
} else if (target > nums[mid]) {
si = mid + 1;
} else {
res[0] = mid; // Update start index
ei = mid - 1; // Continue searching in the left half
}
}
return res; // Return the result array
}
}
Complexity
Time Complexity:
O(log n)
for each binary search, making the total complexityO(log n)
.Space Complexity:
O(1)
since only a constant amount of extra space is used.
Conclusion
In this article, we explored two advanced applications of binary search to handle more complex scenarios: searching in a rotated sorted array and finding the range of a target value in a sorted array. By modifying the standard binary search approach, we efficiently solved these problems with an O(log n)
time complexity. These techniques showcase the versatility of binary search and how small adjustments can make it suitable for a variety of problem-solving contexts.