Find in Mountain Array
Problem Description
You may recall that an array arr is a mountain array if and only if:
arr.length >= 3- There exists some
iwith0 < i < arr.length - 1such that:arr[0] < arr[1] < ... < arr[i - 1] < arr[i]arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Given a mountain array mountainArr, return the minimum index such that mountainArr.get(index) == target. If such an index does not exist, return -1.
You cannot access the mountain array directly. You may only access the array using a MountainArray interface:
MountainArray.get(k)returns the element of the array at indexk(0-indexed).MountainArray.length()returns the length of the array.
Submissions making more than 100 calls to MountainArray.get will be judged Wrong Answer.
Examples
Example 1:Input: array = [1,2,3,4,5,3,1], target = 3 Output: 2 Explanation: 3 exists in the array at index 2 and index 5. The minimum index is 2.
Input: array = [0,1,2,4,2,1], target = 3 Output: -1 Explanation: 3 does not exist in the array.
Constraints
3 <= mountainArr.length() <= 10⁴0 <= target <= 10⁹0 <= mountainArr.get(index) <= 10⁹
Peak Finding and Split Binary Search
To solve this within the 100 API call limit, we use a three-step binary search strategy:
- Find the Peak Index: Run binary search to find the peak of the mountain. At each step, compare
arr[mid]witharr[mid + 1]. Ifarr[mid] < arr[mid + 1], we are in the rising slope, so the peak is to the right; otherwise, we are in the falling slope, so the peak is at or to the left ofmid. - Search the Rising Slope: Run standard binary search for the target on the sorted increasing left half
[0, peak]. If found, return the index immediately. - Search the Falling Slope: If not found on the left, run binary search on the decreasing right half
[peak + 1, n - 1]. Note that the comparison logic is reversed because the slope is decreasing.
Solution 1: Peak Finding with Dual Binary Search
Locate the peak of the mountain array, then execute binary search on both slopes.
/**
* // This is MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* interface MountainArray {
* public int get(int index);
* public int length();
* }
*/
class Solution {
public int findInMountainArray(int target, MountainArray mountainArr) {
int n = mountainArr.length();
// 1. Find peak index
int peak = findPeak(mountainArr, 0, n - 1);
// 2. Binary search on the rising left slope
int leftIdx = binarySearch(mountainArr, target, 0, peak, true);
if (leftIdx != -1) return leftIdx;
// 3. Binary search on the falling right slope
return binarySearch(mountainArr, target, peak + 1, n - 1, false);
}
private int findPeak(MountainArray arr, int left, int right) {
while (left < right) {
int mid = left + (right - left) / 2;
if (arr.get(mid) < arr.get(mid + 1)) {
left = mid + 1; // peak is on the right
} else {
right = mid; // peak is on the left (or is mid itself)
}
}
return left;
}
private int binarySearch(MountainArray arr, int target, int left, int right, boolean ascending) {
while (left <= right) {
int mid = left + (right - left) / 2;
int val = arr.get(mid);
if (val == target) {
return mid;
}
if (ascending) {
if (val < target) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (val > target) {
left = mid + 1; // since descending, target is further right
} else {
right = mid - 1;
}
}
}
return -1;
}
}# """
# This is MountainArray's API interface.
# You should not implement it, or speculate about its implementation
# """
# class MountainArray:
# def get(self, index: int) -> int:
# def length(self) -> int:
class Solution:
def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:
n = mountain_arr.length()
# Find peak index
left, right = 0, n - 1
while left < right:
mid = left + (right - left) // 2
if mountain_arr.get(mid) < mountain_arr.get(mid + 1):
left = mid + 1
else:
right = mid
peak = left
# Binary search on ascending half
left, right = 0, peak
while left <= right:
mid = left + (right - left) // 2
val = mountain_arr.get(mid)
if val == target:
return mid
elif val < target:
left = mid + 1
else:
right = mid - 1
# Binary search on descending half
left, right = peak + 1, n - 1
while left <= right:
mid = left + (right - left) // 2
val = mountain_arr.get(mid)
if val == target:
return mid
elif val > target: # descending check
left = mid + 1
else:
right = mid - 1
return -1/**
* // This is the MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* class MountainArray {
* public:
* int get(int index);
* int length();
* };
*/
class Solution {
private:
int findPeak(MountainArray& arr, int left, int right) {
while (left < right) {
int mid = left + (right - left) / 2;
if (arr.get(mid) < arr.get(mid + 1)) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
int binarySearch(MountainArray& arr, int target, int left, int right, bool ascending) {
while (left <= right) {
int mid = left + (right - left) / 2;
int val = arr.get(mid);
if (val == target) return mid;
if (ascending) {
if (val < target) left = mid + 1;
else right = mid - 1;
} else {
if (val > target) left = mid + 1;
else right = mid - 1;
}
}
return -1;
}
public:
int findInMountainArray(int target, MountainArray& mountainArr) {
int n = mountainArr.length();
int peak = findPeak(mountainArr, 0, n - 1);
int leftIdx = binarySearch(mountainArr, target, 0, peak, true);
if (leftIdx != -1) return leftIdx;
return binarySearch(mountainArr, target, peak + 1, n - 1, false);
}
};Complexity Analysis
- Time Complexity: O(log n) since we execute exactly three binary search phases, each taking O(log n) API calls.
- Space Complexity: O(1) auxiliary space as we track boundaries using simple variables.
Where It Breaks
If the array is not a valid single-peak mountain (e.g. contains multiple local peaks or flat plateaus), the peak finding step fails.
Common Mistakes
- Incorrect binary search logic on decreasing slope: Using ascending slope conditions (
val < targetshifts right) on the decreasing slope, which fails to locate elements. - Too many API calls: Calling
mountainArr.getrepeatedly inside loops instead of caching or comparing adjacent midpoints once, exceeding the 100 call limit.
Frequently Asked Questions
Why does Koko take a peak finding approach? Because the left and right halves are sorted in opposite directions, locating the peak allows us to partition the problem into two standard sorted sub-searches.
What happens if target is at the peak?
The binary search on the rising left slope [0, peak] will find it at the peak index and return it.