First Occurrence in a Sorted Array
Problem and examples
Given a sorted array of integers and a target number key, your task is to find the first occurrence (leftmost index) of key in the array.
If the element is not found, return -1.
| Input Array | Key | First Occurrence Index | Description |
|---|---|---|---|
| [5, 10, 10, 10, 20, 20] | 10 | 1 | 10 appears at indices 1, 2, 3. First occurrence is at index 1 |
| [2, 4, 4, 4, 6, 6, 8] | 4 | 1 | First occurrence of 4 is at index 1 |
| [1, 2, 3, 4, 5] | 6 | -1 | 6 does not exist in the array |
| [1, 1, 1, 1] | 1 | 0 | All elements are 1. First index is 0 |
| [1, 2, 3, 4, 5] | 3 | 2 | Only one occurrence at index 2 |
Explore Find First Occurrence of an Element in a Sorted Array
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
We are given a sorted array and a target number. Our task is to find the first occurrence of that number in the array.
Even though the array is sorted, the same number can appear multiple times. We need the index of the very first one.
For example, consider the array: [1, 2, 2, 2, 3, 4] and the target: 2. The number 2 appears three times, but the first occurrence is at index 1.
Step-by-Step Solution
Step 1: Recognize that the array is sorted
This is a key observation. Because the array is sorted, we can use binary search to quickly narrow down our search space.
Step 2: Modify binary search to continue searching on the left
Normally, binary search stops when it finds the target. But in our case, we need to go further. Once we find the target, we don’t stop—we move to the left side of the array to check if the number appears earlier.
This ensures we always find the first occurrence and not just any one.
Step 3: Edge Case Handling
- Target not present: If the number does not exist in the array at all, we should return
-1. - Single-element array: If the array has only one element, we should still handle it correctly.
- All elements are the target: The algorithm should correctly return index
0.
Why is this efficient?
Instead of checking every element from left to right, we use binary search, which cuts the array in half at each step.
This gives us a time complexity of O(log n), which is much faster than O(n) for large arrays.
Finally
By understanding the nature of the problem (sorted array, repeated elements), and modifying a classic algorithm (binary search), we can solve the problem efficiently and correctly—even with edge cases.
- Initialize
start = 0,end = n - 1, andres = -1to store the result. - While
start ≤ end, calculatemid = start + (end - start) / 2. - If
arr[mid] == key: updateres = midand moveend = mid - 1to search left. - If
arr[mid] < key: movestart = mid + 1. - If
arr[mid] > key: moveend = mid - 1. - After the loop,
reswill contain the first occurrence index or -1 if not found.
Implementation and efficiency
C implementation
#include <stdio.h>
int solve(int n, int key, int arr[]) {
int start = 0, end = n - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
end = mid - 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
int main() {
int arr[] = {5, 10, 10, 10, 20, 20};
int key = 10;
int n = sizeof(arr) / sizeof(arr[0]);
printf("First Occurrence Index: %d\n", solve(n, key, arr));
return 0;
}C++ implementation
#include <iostream>
using namespace std;
int solve(int n, int key, int arr[]) {
int start = 0, end = n - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
end = mid - 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
int main() {
int arr[] = {5, 10, 10, 10, 20, 20};
int key = 10;
int n = sizeof(arr) / sizeof(arr[0]);
cout << "First Occurrence Index: " << solve(n, key, arr) << endl;
return 0;
}Python implementation
def solve(n, key, arr):
start = 0
end = n - 1
res = -1
while start <= end:
mid = start + (end - start) // 2
if arr[mid] == key:
res = mid
end = mid - 1
elif key < arr[mid]:
end = mid - 1
else:
start = mid + 1
return res
arr = [5, 10, 10, 10, 20, 20]
key = 10
print("First Occurrence Index:", solve(len(arr), key, arr))Java implementation
public class FirstOccurrenceFinder {
public static int solve(int n, int key, int[] arr) {
int start = 0, end = n - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
end = mid - 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {5, 10, 10, 10, 20, 20};
int key = 10;
System.out.println("First Occurrence Index: " + solve(arr.length, key, arr));
}
}JavaScript implementation
function solve(n, key, arr) {
let start = 0, end = n - 1, res = -1;
while (start <= end) {
let mid = Math.floor(start + (end - start) / 2);
if (arr[mid] === key) {
res = mid;
end = mid - 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
const arr = [5, 10, 10, 10, 20, 20];
const key = 10;
console.log("First Occurrence Index:", solve(arr.length, key, arr));Go implementation
package main
import "fmt"
func solve(n int, key int, arr []int) int {
start, end := 0, n-1
res := -1
for start <= end {
mid := start + (end - start) / 2
if arr[mid] == key {
res = mid
end = mid - 1
} else if key < arr[mid] {
end = mid - 1
} else {
start = mid + 1
}
}
return res
}
func main() {
arr := []int{5, 10, 10, 10, 20, 20}
key := 10
fmt.Println("First Occurrence Index:", solve(len(arr), key, arr))
}Rust implementation
fn solve(arr: &Vec<i32>, key: i32) -> i32 {
let mut start = 0;
let mut end = arr.len() as i32 - 1;
let mut res = -1;
while start <= end {
let mid = start + (end - start) / 2;
if arr[mid as usize] == key {
res = mid;
end = mid - 1;
} else if key < arr[mid as usize] {
end = mid - 1;
} else {
start = mid + 1;
}
}
res
}
fn main() {
let arr = vec![5, 10, 10, 10, 20, 20];
let key = 10;
println!("First Occurrence Index: {}", solve(&arr, key));
}Kotlin implementation
fun solve(n: Int, key: Int, arr: IntArray): Int {
var start = 0
var end = n - 1
var res = -1
while (start <= end) {
val mid = start + (end - start) / 2
if (arr[mid] == key) {
res = mid
end = mid - 1
} else if (key < arr[mid]) {
end = mid - 1
} else {
start = mid + 1
}
}
return res
}
fun main() {
val arr = intArrayOf(5, 10, 10, 10, 20, 20)
val key = 10
println("First Occurrence Index: ${solve(arr.size, key, arr)}")
}Swift implementation
func solve(_ n: Int, _ key: Int, _ arr: [Int]) -> Int {
var start = 0, end = n - 1, res = -1
while start <= end {
let mid = start + (end - start) / 2
if arr[mid] == key {
res = mid
end = mid - 1
} else if key < arr[mid] {
end = mid - 1
} else {
start = mid + 1
}
}
return res
}
let arr = [5, 10, 10, 10, 20, 20]
let key = 10
print("First Occurrence Index: \(solve(arr.count, key, arr))")TypeScript implementation
function solve(n: number, key: number, arr: number[]): number {
let start = 0, end = n - 1, res = -1;
while (start <= end) {
const mid = Math.floor(start + (end - start) / 2);
if (arr[mid] === key) {
res = mid;
end = mid - 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
const arr = [5, 10, 10, 10, 20, 20];
const key = 10;
console.log("First Occurrence Index:", solve(arr.length, key, arr));Time complexity
| Case | Time | Explanation |
|---|---|---|
| best case | O(1) | The key is found at the mid index in the first iteration. |
| average case | O(log n) | Binary search reduces the search space by half each time. |
| worst case | O(log n) | All elements must be checked in the narrowed space to find the first occurrence. |
Space complexity
O(1)
The algorithm uses only a fixed number of variables regardless of input size.