05 - Ternary Search
Problem¶
Search for a target element in a sorted array by dividing the search interval into three equal parts instead of two.
Intuition¶
Binary Search divides the array into two halves. Ternary Search takes it a step further by dividing the search space into three parts using two midpoints (mid1 and mid2).
Think of it like looking for a house on a street where you have two scouts. Scout A checks the house at ⅓rd of the street, and Scout B checks the house at ⅔rds. Depending on where the target is relative to these two points, you can eliminate ⅔rds of the street in a single step (if lucky) or ⅓rd in the worst case.
Algorithm Steps¶
- Initialize
low = 0andhigh = n - 1. - While
low <= high: - Calculate two midpoints:
mid1 = low + (high - low) / 3mid2 = high - (high - low) / 3
- If
A[mid1] == target, returnmid1. - If
A[mid2] == target, returnmid2. - If
target < A[mid1], search in the first part:high = mid1 - 1. - If
target > A[mid2], search in the third part:low = mid2 + 1. - Otherwise, search in the middle part:
low = mid1 + 1,high = mid2 - 1. - If not found, return -1.
Pseudocode¶
procedure ternarySearch(A, low, high, target)
if high >= low then
mid1 := low + (high - low) / 3
mid2 := high - (high - low) / 3
if A[mid1] == target then return mid1
if A[mid2] == target then return mid2
if target < A[mid1] then
return ternarySearch(A, low, mid1 - 1, target)
else if target > A[mid2] then
return ternarySearch(A, mid2 + 1, high, target)
else
return ternarySearch(A, mid1 + 1, mid2 - 1, target)
end if
return -1
end procedure
Java Code using JCF¶
Using a competitive programming structure (TCS NQT Style).
import java.util.*;
public class Main {
/**
* Ternary Search Implementation (Iterative)
*/
public static int ternarySearch(List<Integer> list, int target) {
int low = 0, high = list.size() - 1;
while (low <= high) {
int mid1 = low + (high - low) / 3;
int mid2 = high - (high - low) / 3;
if (list.get(mid1) == target) return mid1;
if (list.get(mid2) == target) return mid2;
if (target < list.get(mid1)) {
high = mid1 - 1;
} else if (target > list.get(mid2)) {
low = mid2 + 1;
} else {
low = mid1 + 1;
high = mid2 - 1;
}
}
return -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt()) {
int t = sc.nextInt();
while (t-- > 0) {
if (sc.hasNextInt()) {
int n = sc.nextInt();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (sc.hasNextInt()) {
list.add(sc.nextInt());
}
}
Collections.sort(list);
if (sc.hasNextInt()) {
int target = sc.nextInt();
System.out.println(ternarySearch(list, target));
}
}
}
}
sc.close();
}
}
Sample Input and Output¶
Input:
Output:
Complexity¶
| Case | Time Complexity | Space Complexity |
|---|---|---|
| All Cases | \(O(\log_3 n)\) | \(O(1)\) (Iterative) / \(O(\log_3 n)\) (Recursive) |
- Comparison to Binary Search: Ternary search performs more comparisons per iteration than binary search. Even though it has a better logarithmic base (\(\log_3\) vs \(\log_2\)), the extra comparisons usually make it slower in practice on actual computers.
- Sorted Required: Yes.
Example and Dry Run¶
Input: list = [1, 2, 3, 4, 5, 6, 7, 8, 9], target = 5
- low=0, high=8
mid1 = 0 + (8-0)/3 = 2.list[2] = 3.mid2 = 8 - (8-0)/3 = 6.list[6] = 7.5is between3and7.low = 2+1 = 3,high = 6-1 = 5.- New range
[3, 5].mid1 = 3 + (5-3)/3 = 3.list[3] = 4. mid2 = 5 - (5-3)/3 = 5.list[5] = 6.5is between4and6.low = 3+1 = 4,high = 5-1 = 4.mid1 = 4, mid2 = 4.list[4] = 5. Found! Return 4.
Variations¶
- Unimodal Function Optimization: Ternary search is frequently used to find the maximum or minimum of a unimodal function (a function that increases then decreases, or vice versa) where derivatives might be hard to calculate.