162. Find Peak Element

Problem Statement

A peak element is an element that is strictly greater than its neighbors.

Given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.

You may imagine that nums[-1] = nums[n] = -∞. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.

You must write an algorithm that runs in O(log n) time. (link)

Example 1:

Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.

Solution

Brute force Approach

If the i index is the peak then it should satisfy the following condition

nums[i-1]<nums[i]>nums[i+1]

If there is no peak, then the maximum element present in the array is considered a peak. This implies that if there is no peak, the array is sorted in either increasing or decreasing order. Therefore, the peak will be the first element if the array is sorted in descending order, or vice versa.

  1. We need to check whether i satisfies the peak condition or not:

    nums[i-1]<nums[i] && nums[i]>nums[i+1]

  2. If i= 0, there is no need to check the left condition nums[i-1]<nums[i]

  3. similarly if i=n-1 then there is no need to check the right condition nums[i]>nums[i+1]

class Solution {
    public int findPeakElement(int[] nums) {
        int n = nums.length;
        for(int i=0; i<n; i++){
            if((i==0 || nums[i-1]<nums[i]) && (i==n-1 || nums[i]>nums[i+1])) 
                return i;
        }
        return -1;
    }
}

In binary search, the main task is to determine which half of the array to eliminate.

For 1 peak: If there is only one peak, we need to identify the midpoint's relation to the peak.

I. If the midpoint is on the decreasing side, the peak will be on the left. This can be easily identified by checking if nums[mid]>nums[mid+1].

II. "If the midpoint is on the increasing half, then the peak will be towards the right. This can be identified using the condition nums[mid]>nums[mid-1].

For multiple peaks: Our above approach also works if there is more than one peak, as we can return any of the peaks.

So, if we assume there is only one in the given array and solve it, then it will still work. However, the only failure point will be if our algorithm is unable to determine whether we are on the increasing half or decreasing half, i.e., the dip point or local minima.

In that case, we can go in any direction.

Base checks:

  • If there is only one element in the array, then return the element at index 0.

  • Check if the first element is the peak.

  • Check if the last element is the peak.

If the above three base checks fail, then only start the binary search. You can also shrink the search space by starting with a low index of 1 and a high index of n-2. This shrinking will help avoid accessing the -1 and nth index for mid-element comparison. You can safely compare mid with mid-1 and mid+1 without worrying about the index out-of-bounds exception.

class Solution {
    public int findPeakElement(int[] nums) {
        int n = nums.length;
        int low = 0;
        int high = n-1;

        if(n==1) return 0;

        if(nums[0]>nums[1]) return 0;

        if(nums[n-1]>nums[n-2]) return n-1;

        low +=1;
        high-=1;

        while(low<=high){
            int mid = (low+high)>>1;
            if(nums[mid-1]<nums[mid] && nums[mid]> nums[mid+1]) 
                return mid;

            if(nums[mid]>nums[mid-1]){
                low = mid+1;
            } else if(nums[mid]>nums[mid+1]){
                high = mid-1;
            }else{
                low = mid+1;
            }
        }
        return -1;
    }
}