Last 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 last occurrence (last index) of the key in the array.
- If the key appears multiple times, return the index of its last appearance.
- If the key does not exist in the array, return
-1. - If the array is empty, return
-1.
This problem is commonly solved using a modified version of binary search for better efficiency.
| Input Array | Key | Last Occurrence Index | Description |
|---|---|---|---|
| [5, 10, 10, 10, 20, 20] | 10 | 3 | Key 10 appears at indices 1, 2, and 3. Last is at index 3. |
| [1, 2, 3, 4, 5] | 3 | 2 | Key 3 occurs only once at index 2. |
| [1, 1, 1, 1, 1] | 1 | 4 | All elements are the key. Last is at index 4. |
| [1, 2, 4, 5, 6] | 3 | -1 | Key 3 is not present in the array. |
| [1, 2, 3, 4, 5] | 5 | 4 | Key is the last element in the array. |
| [10, 20, 30, 40, 50] | 10 | 0 | Key is the first element, and occurs only once. |
| [] | 7 | -1 | Empty array. No elements to search. |
Explore Find Last 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 called key. Our goal is to find the last occurrence (also called the rightmost index) of this key in the array.
Since the array is sorted, we can use a powerful technique called binary search to solve this efficiently in O(log n) time. However, we need to slightly modify the traditional binary search so that instead of stopping at the first match, we continue looking toward the right side of the array. This way, we ensure that we don’t miss any later occurrences of the same number.
Step-by-Step Solution with Example
Example
Input: arr = [2, 4, 10, 10, 10, 18, 20], key = 10
Expected Output: 4 (since the last occurrence of 10 is at index 4)
Step 1: Initialize Variables
We begin by setting two pointers: start = 0 and end = length of array - 1. We also set a result variable res = -1 to store the index of the last occurrence (if found).
Step 2: Apply Binary Search
We now enter a loop while start <= end. In each iteration, we calculate the middle index: mid = Math.floor((start + end) / 2).
Then, we compare arr[mid] with the key and take action:
- Case 1: arr[mid] == key
We have found an occurrence! But we still want to find if there’s another occurrence further to the right. So, we setres = midand updatestart = mid + 1. - Case 2: arr[mid] < key
The key must be on the right, so we move thestartpointer tomid + 1. - Case 3: arr[mid] > key
The key must be on the left, so we move theendpointer tomid - 1.
Step 3: End of Search
The loop ends when start > end. At this point, the value of res will either hold the last occurrence index or remain -1 if the key wasn't found.
How the Code Handles Edge Cases
- If the key occurs once: We find and return that index.
- If the key occurs multiple times: The algorithm continues to search toward the right, updating the result every time it finds a match, and ultimately returns the last index.
- If the key does not exist: No match will be found, and the result stays at
-1. - If the array is empty: The loop never runs, and
-1is returned immediately.
By continuing the search even after finding a match, we make sure we don’t stop too early. This makes our approach robust, especially when the target number appears multiple times. And because we are cutting the search space in half each time, the time complexity is only O(log n), which is very efficient for large arrays.
- 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 movestart = mid + 1to search towards the right. - If
arr[mid] < key: movestart = mid + 1. - If
arr[mid] > key: moveend = mid - 1. - After the loop,
reswill contain the last occurrence index or -1 if not found.
Implementation and efficiency
C implementation
#include <stdio.h>
int lastOccurrence(int arr[], int n, int key) {
int start = 0, end = n - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
start = 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 n = sizeof(arr) / sizeof(arr[0]);
int key = 10;
printf("Last Occurrence Index: %d\n", lastOccurrence(arr, n, key));
return 0;
}C++ implementation
#include <iostream>
#include <vector>
using namespace std;
int lastOccurrence(const vector<int>& arr, int key) {
int start = 0, end = arr.size() - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
start = mid + 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
int main() {
vector<int> arr = {5, 10, 10, 10, 20, 20};
int key = 10;
cout << "Last Occurrence Index: " << lastOccurrence(arr, key) << endl;
return 0;
}Python implementation
def last_occurrence(arr, key):
start, end = 0, len(arr) - 1
result = -1
while start <= end:
mid = start + (end - start) // 2
if arr[mid] == key:
result = mid
start = mid + 1
elif key < arr[mid]:
end = mid - 1
else:
start = mid + 1
return result
arr = [5, 10, 10, 10, 20, 20]
key = 10
print("Last Occurrence Index:", last_occurrence(arr, key))Java implementation
public class LastOccurrenceFinder {
public static int lastOccurrence(int[] arr, int key) {
int start = 0, end = arr.length - 1, res = -1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (arr[mid] == key) {
res = mid;
start = 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("Last Occurrence Index: " + lastOccurrence(arr, key));
}
}JavaScript implementation
function lastOccurrence(arr, key) {
let start = 0, end = arr.length - 1;
let result = -1;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (arr[mid] === key) {
result = mid;
start = mid + 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return result;
}
const arr = [5, 10, 10, 10, 20, 20];
const key = 10;
console.log("Last Occurrence Index:", lastOccurrence(arr, key));Go implementation
package main
import "fmt"
func lastOccurrence(arr []int, key int) int {
start, end := 0, len(arr)-1
res := -1
for start <= end {
mid := start + (end-start)/2
if arr[mid] == key {
res = mid
start = 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("Last Occurrence Index:", lastOccurrence(arr, key))
}Rust implementation
fn last_occurrence(arr: &[i32], key: i32) -> i32 {
let (mut start, mut end) = (0, 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;
start = mid + 1;
} else if key < arr[mid as usize] {
end = mid - 1;
} else {
start = mid + 1;
}
}
res
}
fn main() {
let arr = [5, 10, 10, 10, 20, 20];
let key = 10;
println!("Last Occurrence Index: {}", last_occurrence(&arr, key));
}Kotlin implementation
fun lastOccurrence(arr: IntArray, key: Int): Int {
var start = 0
var end = arr.size - 1
var result = -1
while (start <= end) {
val mid = start + (end - start) / 2
if (arr[mid] == key) {
result = mid
start = mid + 1
} else if (key < arr[mid]) {
end = mid - 1
} else {
start = mid + 1
}
}
return result
}
fun main() {
val arr = intArrayOf(5, 10, 10, 10, 20, 20)
val key = 10
println("Last Occurrence Index: ${lastOccurrence(arr, key)}")
}Swift implementation
func lastOccurrence(_ arr: [Int], _ key: Int) -> Int {
var start = 0, end = arr.count - 1, result = -1
while start <= end {
let mid = start + (end - start) / 2
if arr[mid] == key {
result = mid
start = mid + 1
} else if key < arr[mid] {
end = mid - 1
} else {
start = mid + 1
}
}
return result
}
let arr = [5, 10, 10, 10, 20, 20]
let key = 10
print("Last Occurrence Index:", lastOccurrence(arr, key))TypeScript implementation
function lastOccurrence(arr: number[], key: number): number {
let start = 0, end = arr.length - 1;
let result = -1;
while (start <= end) {
const mid = Math.floor((start + end) / 2);
if (arr[mid] === key) {
result = mid;
start = mid + 1;
} else if (key < arr[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return result;
}
const arr: number[] = [5, 10, 10, 10, 20, 20];
const key = 10;
console.log("Last Occurrence Index:", lastOccurrence(arr, key));Time complexity
| Case | Time | Explanation |
|---|---|---|
| best case | O(1) | When the key is found at the first mid computation and no further checking is needed. |
| average case | O(log n) | Each iteration halves the search space, leading to logarithmic performance. |
| worst case | O(log n) | In the worst case, the search checks each level of the binary search tree until no more right occurrences are found. |
Space complexity
O(1)
Only a fixed number of variables are used, with no extra memory required.