Given a sorted array that has been rotated at an unknown pivot, search for a given element in O(log n) time. The array is assumed to contain distinct elements.
- Binary search can be modified to search a sorted and rotated array efficiently.
- The element can be searched either by first finding the pivot or by using a single modified binary search.
Examples:
Input: arr[] = {5, 6, 7, 8, 9, 10, 1, 2, 3}, key = 3
Output: Found at index 8Input: arr[] = {5, 6, 7, 8, 9, 10, 1, 2, 3}, key = 30
Output: Not Found
Approaches to Search in a Sorted and Rotated Array
The element can be searched using the following approaches:
1. Find the Pivot and Apply Binary Search
The first approach finds the pivot point, which is the index of the largest element. The array is then divided into two sorted subarrays, and binary search is applied to the appropriate subarray.
Steps
- Find the pivot index where arr[i] > arr[i + 1].
- If no pivot exists, the array is already sorted, so apply binary search to the entire array.
- If the key is equal to the pivot element, return its index.
- If the key is greater than or equal to arr[0], search in the left subarray.
- Otherwise, search in the right subarray.
- Return -1 if the key is not found.
#include <iostream>
#include <vector>
using namespace std;
// Binary search in a sorted range
int binarySearch(const vector<int>& arr, int low, int high, int key)
{
while (low <= high)
{
int mid = low + (high - low) / 2;
if (arr[mid] == key)
return mid;
if (arr[mid] < key)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
// Find the index of the largest element
int findPivot(const vector<int>& arr)
{
int low = 0, high = arr.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (mid < high && arr[mid] > arr[mid + 1])
return mid;
if (mid > low && arr[mid] < arr[mid - 1])
return mid - 1;
if (arr[low] <= arr[mid])
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
// Search for key in a sorted and rotated array
int search(const vector<int>& arr, int key)
{
int n = arr.size();
int pivot = findPivot(arr);
// Array is not rotated
if (pivot == -1)
return binarySearch(arr, 0, n - 1, key);
if (arr[pivot] == key)
return pivot;
if (key >= arr[0])
return binarySearch(arr, 0, pivot - 1, key);
return binarySearch(arr, pivot + 1, n - 1, key);
}
int main()
{
vector<int> arr = {5, 6, 7, 8, 9, 10, 1, 2, 3};
int key = 3;
int index = search(arr, key);
if (index != -1)
cout << "Found at index " << index;
else
cout << "Not Found";
return 0;
}
Output
Found at index 8
Explanation: The pivot is at index 5, where 10 > 1. This divides the array into two sorted parts: {5, 6, 7, 8, 9, 10} and {1, 2, 3}. Since 3 is smaller than arr[0], binary search is performed in the right subarray, where it is found at index 8.
2. Single Binary Search
The search can also be performed using a single modified binary search. At each step, at least one half of the current range is guaranteed to be sorted.
Steps
- Find the middle element.
- If the middle element is the key, return its index.
- Check whether the left half is sorted.
- If the key lies within the sorted left half, search there; otherwise, search the right half.
- If the left half is not sorted, the right half must be sorted.
- Check whether the key lies within the sorted right half and continue accordingly.
- Return -1 if the key is not found.
#include <iostream>
#include <vector>
using namespace std;
// Search key using modified binary search
int search(const vector<int>& arr, int key)
{
int low = 0, high = arr.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (arr[mid] == key)
return mid;
// Left half is sorted
if (arr[low] <= arr[mid])
{
if (arr[low] <= key && key < arr[mid])
high = mid - 1;
else
low = mid + 1;
}
// Right half is sorted
else
{
if (arr[mid] < key && key <= arr[high])
low = mid + 1;
else
high = mid - 1;
}
}
return -1;
}
int main()
{
vector<int> arr = {4, 5, 6, 7, 8, 9, 1, 2, 3};
int key = 6;
int index = search(arr, key);
if (index != -1)
cout << "Index: " << index;
else
cout << "Key not found";
return 0;
}
Output
Index: 2
Explanation: At every step, one half of the current range is sorted. The algorithm determines which half is sorted and checks whether the key can lie in that range. It then discards the other half and continues the binary search.
Handling Duplicates
When duplicate elements are present, the modified binary search can handle them by reducing the search range when the left, middle, and right elements are equal.
#include <iostream>
#include <vector>
using namespace std;
// Search key in a sorted and rotated array
// with duplicate elements
int search(const vector<int>& arr, int key)
{
int low = 0, high = arr.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (arr[mid] == key)
return mid;
// Cannot determine which half is sorted
if (arr[low] == arr[mid] && arr[mid] == arr[high])
{
low++;
high--;
}
// Left half is sorted
else if (arr[low] <= arr[mid])
{
if (arr[low] <= key && key < arr[mid])
high = mid - 1;
else
low = mid + 1;
}
// Right half is sorted
else
{
if (arr[mid] < key && key <= arr[high])
low = mid + 1;
else
high = mid - 1;
}
}
return -1;
}
int main()
{
vector<int> arr = {2, 5, 6, 0, 0, 1, 2};
int key = 0;
int index = search(arr, key);
if (index != -1)
cout << "Found at index " << index;
else
cout << "Not Found";
return 0;
}
Output
Found at index 3
Explanation: When arr[low], arr[mid], and arr[high] are equal, it is not possible to determine which half is sorted. In this case, low and high are moved inward to eliminate duplicate boundary elements.