Find first or last occurrence of a given number in a sorted array

Learn how to find the first or last occurrence of a given number in a sorted array.

Given a sorted array with duplicate values we have to create two different algorithms which will find the first and last occurrence of the given element.

Example

Input:
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9]
5

Output:
4 //Index with the first occurrence
5 //Index with the second occurrence

The best way to find anything in a sorted array is by using binary search. We will implement both recursive and iterative methods for both algorithm.

Find the first occurrence of the given value in the array.

We will be using a modified version of binary search to find the first occurrence of the element in the array, as binary search returns the index of the element as soon as it finds it.

To find the first occurrence, even after finding the element we will keep looking in the lower range to check if the element has occurred before it or not, if it is then return the lowest index.

Iterative method to find the leftmost element in the sorted array

const first = (arr, value) => {
   let low = 0;
   let high = arr.length - 1;
   let result = -1;
   
   //keep looking for all the elements in the array
   while(low <= high){
     //Get the mid
     const mid = Math.ceil((low + high) / 2);
     
     //If an element found
     //Then store the index and look in the lower range for the first occurrence
     if(arr[mid] === value){
       result = mid;
       high = mid - 1;
     }else if(value < arr[mid]){
       //If the value is less than the mid element then looking at the lower range
       high = mid - 1;
     }else{
       //If the value is greater than the mid element then look in the upper range
       low = mid + 1;
     }
   }
   
   //Return the index
   return result;
 }
Input:
const arr = [1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10];
console.log(first(arr, 5));
console.log(first(arr, 6));

Output:
4
6

Recursive method to find the first occurrence of the element in the array

const first = (arr, value, low = 0, high = arr.length - 1, result = -1) => {
  //Search if the array exists
  if(low <= high)  { 
    
    //Get the mid
    const mid = Math.ceil((low+high) / 2);  
    
    //If element found
    //Store the result
    //And the check the lower range to make sure we get the first occurrence
    if(value === arr[mid]){
      result = mid;
      return first(arr, value, low, mid - 1, result);
    }else if(value < arr[mid]){
      //If value is less 
      //Then search in the lower range
      return first(arr, value, low, mid - 1, result);
    }else{
      //Else search in the upper range
      return first(arr, value, mid + 1, high, result);
    }
  } 
  
  //In the end return the result
  return result;
}
Input:
const arr = [1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10];
console.log(first(arr, 5));
console.log(first(arr, 6));

Output:
4
6

Find the last occurrence of the element in the array.

Just like finding the first occurrence to find the last occurrence, we will have to keep looking for the element in the upper range after it is found to make sure we get the last index of the element.

Iterative method to find the rightmost element in the array.

const last = (arr, value) => {
   let low = 0;
   let high = arr.length - 1;
   let result = -1;
   
   //Search till the array exists
   while(low <= high){
     //Get the mid
     const mid = Math.ceil((low + high) / 2);
     
     //If element found
     //Then keep looking for the last element in the upper range
     if(arr[mid] === value){
       result = mid;
       low = mid + 1;
     }else if(value < arr[mid]){
       //Else if value is less than mid element then looking in the lower range
       high = mid - 1;
     }else{
       //Else if value is greater than mid element then look in the upper range
       low = mid + 1;
     }
   }
   
   //Return the result
   return result;
 }
Input:
const arr = [1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10];
console.log(last(arr, 5));
console.log(last(arr, 6));

Output:
5
7

Recursive method to find the last occurrence of the element in the array.

const last = (arr, value, low = 0, high = arr.length - 1, result = -1) => {
  
  //Search if the array exists
  if(low <= high)  { 
    
    //Get the mid
    const mid = Math.ceil((low+high) / 2);  
    
    //If the element found
    //Store the result
    //And keep checking the upper range to get the last occurrence of element
    if(value === arr[mid]){
      result = mid;
      return last(arr, value, mid + 1, high, result);
    } else if(value < arr[mid]){
      //If value is less
      //Then check in the lower range
      return last(arr, value, low, mid - 1, result);
    }else{
      //Else check in the upper range
      return last(arr, value, mid + 1, high, result);
    }
  } 
  
  //In the end return the result
  return result;
}
Input:
const arr = [1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10];
console.log(last(arr, 5));
console.log(last(arr, 6));

Output:
5
7

Time complexity

For both iterative and recursive approaches the time complexity is O(logn).

Space complexity

For the iterative method, space complexity is O(1) and for the recursive, it is O(n) (Considering the call stack).