One dimensional peak finding finds an index whose value is at least as large as its immediate neighbors. Unlike maximum search, it does not require finding the global maximum. Any local peak is enough.
For an array , index is a peak if:
- and
- and
- otherwise, and
Problem
Given an array of length , find an index such that is a peak.
Assume out of bounds neighbors are treated as negative infinity:
With this convention, every nonempty array has at least one peak.
Key Idea
Look at the middle index .
If , then there must be a peak on the right side. Otherwise, there must be a peak at or on the left side.
This gives a binary-search-like algorithm, even though the array does not need to be sorted.
Algorithm
peak_finding_1d(A):
l = 0
r = length(A) - 1
while l < r:
m = l + (r - l) // 2
if A[m] < A[m + 1]:
l = m + 1
else:
r = m
return lExample
Let
The algorithm may return index , because:
and
So index is a peak.
Correctness
The algorithm maintains the invariant that the current interval contains at least one peak.
If , then the array rises from to . Moving right from , either values continue rising until the right boundary, or eventually stop rising. In both cases, there is a peak in .
If , then there is a peak in by the same argument in the left direction.
Each step keeps an interval containing a peak and strictly reduces its size. When , the remaining index must be a peak.
Complexity
| case | time |
|---|---|
| all cases |
Space:
Comparison with Maximum Search
| method | result | time |
|---|---|---|
| maximum search | global maximum | |
| one dimensional peak finding | any local peak |
Peak finding is faster because it asks for a weaker result.
When to Use
Use one dimensional peak finding when:
- any local optimum is acceptable
- the array is not sorted
- the data has hill-like or valley-like structure
- logarithmic time is desired
Notes
- The returned peak may not be unique.
- The algorithm works with equal adjacent values.
- For a strict peak, special handling is needed when duplicates occur.
Implementation
def peak_finding_1d(a):
if not a:
return -1
l, r = 0, len(a) - 1
while l < r:
m = l + (r - l) // 2
if a[m] < a[m + 1]:
l = m + 1
else:
r = m
return lfunc PeakFinding1D(a []int) int {
if len(a) == 0 {
return -1
}
l, r := 0, len(a)-1
for l < r {
m := l + (r-l)/2
if a[m] < a[m+1] {
l = m + 1
} else {
r = m
}
}
return l
}