Search an element in a sorted and rotated array with duplicates
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++
// 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
// 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
# 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#
// 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 |
Javascript
<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++
// 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; } |
Java
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)); } } |
Python3
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 |
C#
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
// 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)
Please Login to comment...