Find First and Last Index of Element in Sorted Array

The first index of the element is the very first occurrence when iterated from the beginning or forward direction, and the last index of the element is the first occurrence when iterated from the end or backward directions.
let's take some examples

1, 2, 3, 3, 3, 4, 5 and the target is 3, so the first index is 2 and the last index is 4

2, 2, 2, 2, 2, 2, 2 and the target is 2, so the first index is 0 and the last index is 6

1, 1, 1, 1, 2, 3, 4, 5 and the target is 1, so the first index is 0 and the last index is 3

1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5 and the target is 5, so the first index is 4 and the last index is 10

1, 2, 3, 4, 5 and the target is 6, so the first index is -1 and the last index is -1

1, 2, 3, 4, 5 and the target is 3, so the first index is 2 and the last index is 2

If need to find a target element in a sorted array, find the pattern and think of a Binary Search first.

If the target element is found, keep it as a possible answer and search for the left and right sub-array.

package org.wesome.dsalgo;

public class FirstAndLastIndex {
    public static int[] firstAndLastIndex(int[] arr, int target) {
        int[] firstAndLastIndex = {-1, -1};
//        search for the first index of the target in an array
        firstAndLastIndex[0] = binarySearch(arr, target, true);
//        if firstIndx is already -1, it means the target is not present in the array, so don't need to check for the last Index
        if (firstAndLastIndex[0] != -1) {
//        search for the last index of the target in an array
            firstAndLastIndex[1] = binarySearch(arr, target, false);
        }
        return firstAndLastIndex;
    }

    public static int binarySearch(int[] arr, int target, boolean findFirstIndx) {
        int start = 0, end = arr.length - 1;
        int indx = -1;
        while (start <= end) {
            int mid = start + (end - start) / 2;
            // If the target element is present in the middle itself
            if (arr[mid] == target) {
//                the mid is a potential answer, but there is a possibility that there might be more duplicate elements might occur on the left side and right side
                indx = mid;
//                if searching for the first index then need to perform a binary search on the left side of the mid, so update the end to mid + 1
                if (findFirstIndx) {
                    end = mid - 1;
                }
//                if searching for the last index then need to perform a binary search on the right side of the mid, so the update start to mid + 1
                else {
                    start = mid + 1;
                }
            }
            // In ascending order sorted array, If the target is smaller than mid-element, then it can only be present in left sub-array
            else if (arr[mid] > target) {
                end = mid - 1;
            }
            // Else the element can only be present in right sub-array
            else {
                start = mid + 1;
            }
        }
        return indx;
    }
}
package org.wesome.dsalgo;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.wesome.dsalgo.FirstAndLastIndex.firstAndLastIndex;

public class FirstAndLastIndexTest {
    @Test
    void firstAndLastIndexTest1() {
        int[] arr = new int[]{1, 2, 3, 3, 3, 4, 5};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 3);
        Assertions.assertArrayEquals(new int[]{2, 4}, firstAndLastIndex);
    }

    @Test
    void firstAndLastIndexTest2() {
        int[] arr = new int[]{2, 2, 2, 2, 2, 2, 2};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 2);
        Assertions.assertArrayEquals(new int[]{0, 6}, firstAndLastIndex);
    }

    @Test
    void firstAndLastIndexTest3() {
        int[] arr = new int[]{1, 1, 1, 1, 2, 3, 4, 5};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 1);
        Assertions.assertArrayEquals(new int[]{0, 3}, firstAndLastIndex);
    }

    @Test
    void firstAndLastIndexTest4() {
        int[] arr = new int[]{1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 5);
        Assertions.assertArrayEquals(new int[]{4, 10}, firstAndLastIndex);
    }

    @Test
    void firstAndLastIndexTest5() {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 6);
        Assertions.assertArrayEquals(new int[]{-1, -1}, firstAndLastIndex);
    }

    @Test
    void firstAndLastIndexTest6() {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int[] firstAndLastIndex = firstAndLastIndex(arr, 3);
        Assertions.assertArrayEquals(new int[]{2, 2}, firstAndLastIndex);
    }
}
plugins {
    id 'java'
    id "io.freefair.lombok" version "6.4.1"
}

group = 'org.wesome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2'
}

test {
    useJUnitPlatform()
}

The algorithm has time complexity of O(log N) and space complexity of O(log N)

follow us on