Find the maximum or minimum of a unimodal function defined on discrete indices.
Discrete ternary search finds the maximum or minimum of a unimodal function defined over integer indices. A function is unimodal if it strictly increases up to a point and then strictly decreases, or the reverse.
Unlike binary search, which relies on a monotone predicate, ternary search relies on a unimodal shape.
Problem
Given a function defined on integer indices , find an index such that is maximum.
Assume:
Key Idea
Divide the interval into three parts using two midpoints:
Compare and :
- If , the maximum lies in
- Otherwise, it lies in
This reduces the search space.
Algorithm
ternary_search_discrete(f, l, r):
while r - l > 3:
m1 = l + (r - l) // 3
m2 = r - (r - l) // 3
if f(m1) < f(m2):
l = m1 + 1
else:
r = m2 - 1
best = l
for i from l to r:
if f(i) > f(best):
best = i
return bestExample
Let
The function increases up to and decreases afterward.
f(i)=-(i-4)^2+10
The maximum occurs at .
Correctness
At each step, the algorithm discards one third of the interval while preserving the region containing the maximum.
Because the function is unimodal:
- If , the left third cannot contain the maximum
- If , the right third cannot contain the maximum
The remaining interval always contains the optimal point.
The final small interval is scanned directly to ensure correctness on discrete indices.
Complexity
| phase | cost |
|---|---|
| iterations | |
| final scan | |
| total |
Each iteration reduces the interval to about two thirds of its size.
Space:
Comparison
| method | requirement | time |
|---|---|---|
| binary search | monotone predicate | |
| ternary search | unimodal function |
Binary search finds boundaries. Ternary search finds extrema.
When to Use
- Optimization over discrete domains
- Peak finding in unimodal arrays
- Problems where derivative information is unavailable
Notes
- Final linear scan is necessary because indices are discrete
- Works for both maximum and minimum with condition reversal
Implementation
def ternary_search_discrete(f, l, r):
while r - l > 3:
m1 = l + (r - l) // 3
m2 = r - (r - l) // 3
if f(m1) < f(m2):
l = m1 + 1
else:
r = m2 - 1
best = l
for i in range(l, r + 1):
if f(i) > f(best):
best = i
return bestfunc TernarySearchDiscrete(f func(int) int, l, r int) int {
for r-l > 3 {
m1 := l + (r-l)/3
m2 := r - (r-l)/3
if f(m1) < f(m2) {
l = m1 + 1
} else {
r = m2 - 1
}
}
best := l
for i := l; i <= r; i++ {
if f(i) > f(best) {
best = i
}
}
return best
}