🧠
Modified Binary Search (Recursive)
💡 This approach is a recursive version of the iterative binary search, useful to understand recursion and divide-and-conquer strategies.
Intuition
Recursively check the middle element and decide which half to search based on the slope between mid and mid+1.
Algorithm
- Define a recursive function with low and high indices.
- If low == high, return low as peak index.
- Calculate mid = (low + high) // 2.
- If nums[mid] < nums[mid + 1], recurse on right half (mid+1 to high).
- Else recurse on left half (low to mid).
💡 The recursion breaks the problem into smaller parts, focusing on the half that must contain a peak.
def findPeakElement(nums):
def binarySearch(low, high):
if low == high:
return low
mid = (low + high) // 2
if nums[mid] < nums[mid + 1]:
return binarySearch(mid + 1, high)
else:
return binarySearch(low, mid)
return binarySearch(0, len(nums) - 1)
# Example usage
if __name__ == '__main__':
print(findPeakElement([1, 2, 3, 1])) # Output: 2
Line Notes
def binarySearch(low, high):Helper recursive function with boundaries
if low == high:Base case: single element is peak
mid = (low + high) // 2Calculate middle index
if nums[mid] < nums[mid + 1]Decide which half to recurse on
public class Solution {
public int findPeakElement(int[] nums) {
return binarySearch(nums, 0, nums.length - 1);
}
private int binarySearch(int[] nums, int low, int high) {
if (low == high) return low;
int mid = low + (high - low) / 2;
if (nums[mid] < nums[mid + 1]) {
return binarySearch(nums, mid + 1, high);
} else {
return binarySearch(nums, low, mid);
}
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.findPeakElement(new int[]{1, 2, 3, 1})); // 2
}
}
Line Notes
return binarySearch(nums, 0, nums.length - 1);Start recursion with full array
if (low == high) return low;Base case: peak found
int mid = low + (high - low) / 2;Calculate mid safely
if (nums[mid] < nums[mid + 1])Choose right half if slope goes up
#include <iostream>
#include <vector>
using namespace std;
int binarySearch(vector<int>& nums, int low, int high) {
if (low == high) return low;
int mid = low + (high - low) / 2;
if (nums[mid] < nums[mid + 1]) {
return binarySearch(nums, mid + 1, high);
} else {
return binarySearch(nums, low, mid);
}
}
int findPeakElement(vector<int>& nums) {
return binarySearch(nums, 0, nums.size() - 1);
}
int main() {
vector<int> nums = {1, 2, 3, 1};
cout << findPeakElement(nums) << endl; // 2
return 0;
}
Line Notes
if (low == high) return low;Base case for recursion
int mid = low + (high - low) / 2;Calculate mid index safely
if (nums[mid] < nums[mid + 1])Decide which half to recurse on
return binarySearch(nums, 0, nums.size() - 1);Start recursion with full array
function findPeakElement(nums) {
function binarySearch(low, high) {
if (low === high) return low;
const mid = Math.floor((low + high) / 2);
if (nums[mid] < nums[mid + 1]) {
return binarySearch(mid + 1, high);
} else {
return binarySearch(low, mid);
}
}
return binarySearch(0, nums.length - 1);
}
// Example usage
console.log(findPeakElement([1, 2, 3, 1])); // 2
Line Notes
function binarySearch(low, high)Recursive helper function
if (low === high) return low;Base case: found peak
const mid = Math.floor((low + high) / 2);Calculate mid index
if (nums[mid] < nums[mid + 1])Choose right half if slope goes up
TimeO(log n)
SpaceO(log n)
Recursion depth is logarithmic, so time is O(log n). Space is O(log n) due to recursion call stack.
💡 For n=100,000, about 17 recursive calls are made, which is efficient but uses stack space.
Interview Verdict: Accepted and optimal but uses recursion stack
This approach is elegant but may risk stack overflow on very large inputs; iterative is safer.