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)