Open In App

Search an element in a sorted and rotated array with duplicates

Last Updated : 27 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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:
arr[0] = 3

Input: 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>


Output

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));


Output

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) 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads