Given an array arr[] which is sorted and rotated, the task is to find an element in the rotated array (with duplicates) in O(log n) time.
Note: Print the index where the key exists. In case of multiple answer print any of them
Examples:
Input: arr[] = {3, 3, 3, 1, 2, 3}, key = 3
Output: 0
arr[0] = 3Input: arr[] = {3, 3, 3, 1, 2, 3}, key = 11
Output: -1
11 is not present in the given array.
Approach: The idea is the same as the previous one without duplicates. The only difference is that due to the existence of duplicates, arr[low] == arr[mid] could be possible, the first half could be out of order (i.e. not in the ascending order, e.g. {3, 1, 2, 3, 3, 3, 3}) and we have to deal this case separately.
In that case, it is guaranteed that arr[high] also equal to arr[mid], so the condition arr[mid] == arr[low] == arr[high] can be checked before the original logic, and if so then move left and right both towards the middle by 1 and repeat.
Below is the implementation of the above approach:
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std;
// Function to return the index of the // key in arr[l..h] if the key is present // otherwise return -1 int search( int arr[], int l, int h, int key)
{ if (l > h)
return -1;
int mid = l + (h - l) / 2;
if (arr[mid] == key)
return mid;
// The tricky case, just update left and right
if ((arr[l] == arr[mid])
&& (arr[h] == arr[mid]))
{
++l;
--h;
return search(arr, l, h, key);
}
// If arr[l...mid] is sorted
if (arr[l] <= arr[mid]) {
// As this subarray is sorted, we can quickly
// check if key lies in any of the halves
if (key >= arr[l] && key <= arr[mid])
return search(arr, l, mid - 1, key);
// If key does not lie in the first half
// subarray then divide the other half
// into two subarrays such that we can
// quickly check if key lies in the other half
return search(arr, mid + 1, h, key);
}
// If arr[l..mid] first subarray is not sorted
// then arr[mid... h] must be sorted subarray
if (key >= arr[mid] && key <= arr[h])
return search(arr, mid + 1, h, key);
return search(arr, l, mid - 1, key);
} // Driver code int main()
{ int arr[] = { 3, 3, 1, 2, 3, 3 };
int n = sizeof (arr) / sizeof ( int );
int key = 3;
cout << search(arr, 0, n - 1, key);
return 0;
} |
// Java implementation of the approach class GFG
{ // Function to return the index of the
// key in arr[l..h] if the key is present
// otherwise return -1
static int search( int arr[], int l, int h, int key)
{
if (l > h)
return - 1 ;
int mid = l + (h - l) / 2 ;
if (arr[mid] == key)
return mid;
// The tricky case, just update left and right
if ((arr[l] == arr[mid])
&& (arr[h] == arr[mid]))
{
l++;
h--;
return search(arr,l,h,key);
}
// If arr[l...mid] is sorted
else if (arr[l] <= arr[mid])
{
// As this subarray is sorted, we can quickly
// check if key lies in any of the halves
if (key >= arr[l] && key <= arr[mid])
return search(arr, l, mid - 1 , key);
// If key does not lie in the first half
// subarray then divide the other half
// into two subarrays such that we can
// quickly check if key lies in the other half
else
return search(arr, mid + 1 , h, key);
}
// If arr[l..mid] first subarray is not sorted
// then arr[mid... h] must be sorted subarray
else if (key >= arr[mid] && key <= arr[h])
return search(arr, mid + 1 , h, key);
return search(arr, l, mid - 1 , key);
}
// Driver code
public static void main (String[] args)
{
int arr[] ={ 3 , 3 , 1 , 2 , 3 , 3 };
int n = arr.length;
int key = 3 ;
System.out.println(search(arr, 0 , n - 1 , key));
}
} // This code is contributed by AnkitRai01 |
# Python3 implementation of the approach # Function to return the index of the # key in arr[l..h] if the key is present # otherwise return -1 def search(arr, l, h, key) :
if (l > h) :
return - 1 ;
mid = (l + h) / / 2 ;
if (arr[mid] = = key) :
return mid;
# The tricky case, just update left and right
if ((arr[l] = = arr[mid]) and (arr[h] = = arr[mid])) :
l + = 1 ;
h - = 1 ;
return search(arr, l, h, key)
# If arr[l...mid] is sorted
if (arr[l] < = arr[mid]) :
# As this subarray is sorted, we can quickly
# check if key lies in any of the halves
if (key > = arr[l] and key < = arr[mid]) :
return search(arr, l, mid - 1 , key);
# If key does not lie in the first half
# subarray then divide the other half
# into two subarrays such that we can
# quickly check if key lies in the other half
return search(arr, mid + 1 , h, key);
# If arr[l..mid] first subarray is not sorted
# then arr[mid... h] must be sorted subarray
if (key > = arr[mid] and key < = arr[h]) :
return search(arr, mid + 1 , h, key);
return search(arr, l, mid - 1 , key);
# Driver code if __name__ = = "__main__" :
arr = [ 3 , 3 , 1 , 2 , 3 , 3 ];
n = len (arr);
key = 3 ;
print (search(arr, 0 , n - 1 , key));
# This code is contributed by AnkitRai01 |
// C# implementation of the approach using System;
class GFG
{ // Function to return the index of the
// key in arr[l..h] if the key is present
// otherwise return -1
static int search( int []arr, int l, int h, int key)
{
if (l > h)
return -1;
int mid = l + (h - l) / 2;
if (arr[mid] == key)
return mid;
// The tricky case, just update left and right
if ((arr[l] == arr[mid])
&& (arr[h] == arr[mid]))
{
++l;
--h;
return search(arr, l, h, key)
}
// If arr[l...mid] is sorted
if (arr[l] <= arr[mid])
{
// As this subarray is sorted, we can quickly
// check if key lies in any of the halves
if (key >= arr[l] && key <= arr[mid])
return search(arr, l, mid - 1, key);
// If key does not lie in the first half
// subarray then divide the other half
// into two subarrays such that we can
// quickly check if key lies in the other half
return search(arr, mid + 1, h, key);
}
// If arr[l..mid] first subarray is not sorted
// then arr[mid... h] must be sorted subarray
if (key >= arr[mid] && key <= arr[h])
return search(arr, mid + 1, h, key);
return search(arr, l, mid - 1, key);
}
// Driver code
public static void Main ()
{
int []arr = { 3, 3, 1, 2, 3, 3 };
int n = arr.Length;
int key = 3;
Console.WriteLine(search(arr, 0, n - 1, key));
}
} // This code is contributed by AnkitRai01 |
<script> // Javascript implementation of the approach
// Function to return the index of the
// key in arr[l..h] if the key is present
// otherwise return -1
function search(arr, l, h, key)
{
if (l > h)
return -1;
let mid = parseInt((l + h) / 2, 10);
if (arr[mid] == key)
return mid;
// The tricky case, just update left and right
if ((arr[l] == arr[mid])
&& (arr[h] == arr[mid]))
{
++l;
--h;
return search(arr, l, h, key)
}
// If arr[l...mid] is sorted
if (arr[l] <= arr[mid])
{
// As this subarray is sorted, we can quickly
// check if key lies in any of the halves
if (key >= arr[l] && key <= arr[mid])
return search(arr, l, mid - 1, key);
// If key does not lie in the first half
// subarray then divide the other half
// into two subarrays such that we can
// quickly check if key lies in the other half
return search(arr, mid + 1, h, key);
}
// If arr[l..mid] first subarray is not sorted
// then arr[mid... h] must be sorted subarray
if (key >= arr[mid] && key <= arr[h])
return search(arr, mid + 1, h, key);
return search(arr, l, mid - 1, key);
}
let arr = [ 3, 3, 1, 2, 3, 3 ];
let n = arr.length;
let key = 3;
document.write(search(arr, 0, n - 1, key));
</script> |
4
Time Complexity: O(log N), where n represents the size of the given array. If all the elements are same, we may end up doing a linear search.
Auxiliary Space: O(logN) due to recursive stack space.
This approach is better than the recursive one as no auxiliary space is required in this case
// C++ implementation of the above approach using iterative // version of binary search #include <bits/stdc++.h> using namespace std;
int search( int arr[], int low, int high, int key)
{ while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == key) {
// if we have found our target element
// return the index of target element
return mid;
}
if (arr[mid] == arr[low] && arr[mid] == arr[high]) {
// It may happen in case of duplicates
++low;
--high;
continue ;
}
if (arr[low] <= arr[mid]) {
// This means array is sorted from index low to
// mid We will check that if target element lies
// in left half or not
if (key >= arr[low] && key < arr[mid])
high = mid - 1;
else
// This means that our target lies in other
// half of array So we shift low to mid+1 to
// search in right half
low = mid + 1;
}
else {
// This means array is sorted between mid and
// high index
// This will check our target element is
// in right half or not
if (key <= arr[high] && key > arr[mid])
low = mid + 1;
else
// Means our target is in left half
high = mid - 1;
}
}
// If target element is not present
return -1;
} // Driver Code int main()
{ int arr[] = { 3, 3, 1, 2, 3, 3 };
int n = sizeof (arr) / sizeof (arr[0]);
int key = 3;
cout << search(arr, 0, n - 1, key) << endl;
return 0;
} |
import java.util.Scanner;
public class Main {
public static int search( int [] arr, int low, int high, int key) {
while (low <= high) {
int mid = low + (high - low) / 2 ;
if (arr[mid] == key) {
// if we have found our target element
// return the index of target element
return mid;
}
if (arr[mid] == arr[low] && arr[mid] == arr[high]) {
// It may happen in case of duplicates
++low;
--high;
continue ;
}
if (arr[low] <= arr[mid]) {
// This means array is sorted from index low to
// mid We will check that if target element lies
// in left half or not
if (key >= arr[low] && key < arr[mid])
high = mid - 1 ;
else
// This means that our target lies in other
// half of array So we shift low to mid+1 to
// search in right half
low = mid + 1 ;
}
else {
// This means array is sorted between mid and
// high index
// This will check our target element is
// in right half or not
if (key <= arr[high] && key > arr[mid])
low = mid + 1 ;
else
// Means our target is in left half
high = mid - 1 ;
}
}
// If target element is not present
return - 1 ;
}
public static void main(String[] args) {
int [] arr = { 3 , 3 , 1 , 2 , 3 , 3 };
int n = arr.length;
int key = 3 ;
System.out.println(search(arr, 0 , n - 1 , key));
}
} |
def search(arr, low, high, key):
while low < = high:
mid = low + (high - low) / / 2
if arr[mid] = = key:
# if we have found our target element
# return the index of target element
return mid
if arr[mid] = = arr[low] and arr[mid] = = arr[high]:
# It may happen in case of duplicates
low + = 1
high - = 1
continue
if arr[low] < = arr[mid]:
# This means array is sorted from index low to
# mid We will check that if target element lies
# in left half or not
if key > = arr[low] and key < arr[mid]:
high = mid - 1
else :
# This means that our target lies in other
# half of array So we shift low to mid+1 to
# search in right half
low = mid + 1
else :
# This means array is sorted between mid and
# high index
# This will check our target element is
# in right half or not
if key < = arr[high] and key > arr[mid]:
low = mid + 1
else :
# Means our target is in left half
high = mid - 1
# If target element is not present
return - 1
# Driver Code arr = [ 3 , 3 , 1 , 2 , 3 , 3 ]
n = len (arr)
key = 3
print (search(arr, 0 , n - 1 , key))
# This code is contributed by Prince Kumar |
using System;
class MainClass {
public static int Search( int [] arr, int low, int high, int key) {
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == key) {
// if we have found our target element
// return the index of target element
return mid;
}
if (arr[mid] == arr[low] && arr[mid] == arr[high]) {
// It may happen in case of duplicates
++low;
--high;
continue ;
}
if (arr[low] <= arr[mid]) {
// This means array is sorted from index low to
// mid We will check that if target element lies
// in left half or not
if (key >= arr[low] && key < arr[mid])
high = mid - 1;
else
// This means that our target lies in other
// half of array So we shift low to mid+1 to
// search in right half
low = mid + 1;
}
else {
// This means array is sorted between mid and
// high index
// This will check our target element is
// in right half or not
if (key <= arr[high] && key > arr[mid])
low = mid + 1;
else
// Means our target is in left half
high = mid - 1;
}
}
// If target element is not present
return -1;
}
public static void Main() {
int [] arr = { 3, 3, 1, 2, 3, 3 };
int n = arr.Length;
int key = 3;
Console.WriteLine(Search(arr, 0, n - 1, key));
}
} |
// JavaScript implementation of the above approach function search(arr, low, high, key) {
while (low <= high) {
let mid = Math.floor(low + (high - low) / 2);
if (arr[mid] === key) {
// if we have found our target element
// return the index of target element
return mid;
}
if (arr[mid] === arr[low] && arr[mid] === arr[high]) {
// It may happen in case of duplicates
low++;
high--;
continue ;
}
if (arr[low] <= arr[mid]) {
// This means array is sorted from index low to
// mid We will check that if target element lies
// in left half or not
if (key >= arr[low] && key < arr[mid]) {
high = mid - 1;
} else {
// This means that our target lies in other
// half of array So we shift low to mid+1 to
// search in right half
low = mid + 1;
}
} else {
// This means array is sorted between mid and
// high index
// This will check our target element is
// in right half or not
if (key <= arr[high] && key > arr[mid]) {
low = mid + 1;
} else {
// Means our target is in left half
high = mid - 1;
}
}
}
// If target element is not present
return -1;
} // Driver code let arr = [3, 3, 1, 2, 3, 3]; let n = arr.length; let key = 3; console.log(search(arr, 0, n - 1, key)); |
4
Time Complexity: O(N), where n represents the size of the given array. If all the elements are same, we may end up doing a linear search.
Auxiliary Space: O(1)