How to find peak elements in an array when there are multiple peaks?
Asked Answered
P

6

6

For an array with single peak element, it could be done in o(logn) using binary search, however in case of multiple peak elements in an array what approach should we use ?

---Putting some more information ---- A peak element is something which is greater then it's neighbors for instance, look at the below array,

[1,3,20,4,1,0,7,5,2]

there are 2 peaks in it, 20 and 7.

We need to design an algorithm to find the peak elements in this array.

Poche answered 16/8, 2017 at 12:36 Comment(13)
Just sort it by value?Vilmavim
What exactly are multiple peaks? The max value, occurring multiple times? The array needs to be sorted for binary search. If it's sorted, these peaks must be right next to each other, so finding them isn't really an issue, right?Moneymaker
@GillesLesire Sorting is O(n log n), linear scanning is O(n), max elements in ordered array are in the end, so for a sorted array complexity should be O(1). Have no idea where O(log n) came from.Sulfa
@Moneymaker Multiple peaks may mean multiple number of values in the series which are significantly higher than the other values, though, not necessarily equal to each other. We see this sort of peaks in spectrum (frequency) analysis, for example. If it is this kind of situation, then sorting would not help much if the original index of the value is not also somehow stored. Because in such situation, the index may have more importance than the value of the peak.Howlyn
@Deniz ok, I get it. But it's so far away from an "array with a single peak element" that the OP mentioned that I can't even begin to point out the differences in the solution...Moneymaker
@Moneymaker I agree. If the OP is talking about a rather mathematical problem, which I guess he is, then I also wouldn't expect to see any binary search algorithms anywhere. He probably first needs to define what a "peak" is. Is it just a value that's greater than the others, or is it a value that's "way greater" than the others? How much is "way greater"? I think the problem is not defined well enough yet.Howlyn
Have added some more information in the question. Please take a look at it and let me know if still there are some open questions on it. Apologies for the open ended questionPoche
@Poche how did you intend to search for one peak in O(log n)? It's clearly impossible as described. One peak or many, you will need to scan the whole array, O(n) time. Pay attention to first and last elements.Sulfa
For a single peak element, we can easily do it via binary search. Search the middle element first compare with its neighbors and then subsequently move leftwards or to the right side of the middle element. Find index of middle element Compare middle element with its neighbours (if neighbours exist) If middle element is not peak and its left neighbor is greater than it,then left half must have a peak element If middle element is not peak and its right neighbor is greater than it, then right half must have a peak elementPoche
@Poche Oh. So first or last element which is greater than its only neighbor is considered a peak. Still, for array 0 0 0 42 0 0 0 0 0 0 0 your strategy fails and there is no constraint that elements can't be equal (even example in your post has two 1s).Sulfa
yes there shoudl be a check for equal to as well. We can add this as well.In my example we ll either search on the right side of the middle element or left side of mid element so there would not be any equal to constraint required. However, through the algo which I have defined we cannot find multiple peaks. Any guesses on it ?Poche
You could define a treshold maybe. Say A is your array and if the change between A[i] and A[i+1] is more than five times the value of A[i] "and" if A[i+2] is less than A[i+1], then A[i+1] is a peak. But as you see, first, you need to define a treshold or a good definition of a peak that would fit your problem. It entirely depends on the nature of the problem. And this would work only for sudden jumps, like in your example array. A peak may not happen that suddenly.Howlyn
good one..the only problem with this is that it will not be dynamic..Poche
R
2

I might have not understand your question since, finding single peak can be done in O(logn) requires array to be sorted at first place.

I would advise you to store a difference array which will generate an output like: [1,3,20,4,1,0,7,5,2] => [1, 1,-1,-1,-1, 1,-1,-1] which is simply generate an array of size n - 1 and place the direction of increase in the array. This can be done in O(n) single pass.

In the second pass you will look for [1, -1] pairs this is the place where peak occurs.

If you want to find peaks in the start and end you need to check if start is -1, and end is 1.

Hope this helps.

Refugee answered 16/8, 2017 at 13:40 Comment(3)
anything that you could think of in o(logn)Poche
if you have single array it is impossible.Refugee
If there is exactly one peak then it's a binary search: O(log n). If there could be any number of peaks, that means you have to check ALL elements is a way or other, so it cannot be faster than O (n)Coercive
H
2

I recently faced the similar problem on a programming website but there was another important constraint other than finding peaks. Firstly, there can be multiple peaks, but there can also be plateaus! A plateau is something that occurs in an arr: [1,2,2,2,1] and in this case we have to return the peak to be 2. In the problem we are also asked to return the first position where the peak occurs, so in this case it will be position = 1. The only case, that we have to remain careful about is that in arr: [1,2,2,2,3,4,5,1], there is peak with 5 in the second last position but there is no plateau even if there is a series of duplicates which look like a plateau in the first glance.

So the basic algorithm that I thought about was using a difference array as already suggested using {1,0,-1} where we use 0 when we get a series of duplicates in a continuous stream. Whenever we get a 0 while checking the difference array, we start looking for the first non zero entry, whether it is 1 or -1 and output accordingly. But again we have to remain careful that may be the Difference array looks like Diff = [-1,1,-1,1,0,0,0], in which case there is no plateau and only one peak. The python code looks like the following, when arr is given as input:

n = len(arr)
if arr == []:
    return {"pos":[],"peaks":[]}
Diff = []
for i in range(0,n-1):
    if arr[i]< arr[i+1]:
        Diff.append(1)
    elif arr[i] == arr[i+1]:
        Diff.append(0)
    if arr[i] > arr[i+1]:
        Diff.append(-1)
pos = []
peaks = []
j = 0
for i in range(0,n-2):
    if Diff[i] == 1 and Diff[i+1] == -1:
        pos.append(i+1)
        peaks.append(arr[i+1])
    if Diff[i] == 1 and Diff[i+1] == 0:
        if Diff[i+1:] == [Diff[i+1]]:
            break
        j = i+1
        while(Diff[j] == 0 and j < n-2):
            j = j+1
        if Diff[j] == -1:
            pos.append(i+1)
            peaks.append(arr[i+1])


return {"pos":pos, "peaks":peaks} 
Heir answered 26/1, 2020 at 10:48 Comment(0)
A
0

For finding all the peak elements when having multiple peaks.

class Solution(object):
    def findPeakElement(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        left, right = 0, len(nums) - 1
        while left < right:
            mid = left + right >> 1
            if nums[mid] < nums[mid + 1]:
                left = mid + 1
            else:
                right = mid
        return left
Apocalypse answered 15/2, 2019 at 17:50 Comment(0)
B
0
int arr[] = {50, 12, 13, 20, 16, 19, 11, 7, 24};
int size = sizeof(arr) / sizeof(arr[0]);

int peak_arr[size / 2];
int i, j, k = 0;
int next, previous = 0;

for(i = 0; i < size; i++){
    if(i + 1 == size){
        next = 0;
    }
    else{
        next = arr[i + 1];
    }
    
    if(arr[i] > next && arr[i] >= previous){
        peak_arr[k++] = arr[i];
    }
    previous = arr[i];
}
Beauregard answered 27/11, 2020 at 10:8 Comment(1)
Although your answer might be the correct solution, it would help to have some explanation about your code.Grazing
C
0

Finding multiple peak elemets using a recursive approach.

def Div(lst, low, high):
    mid = (low + high)//2
    if low > high:
        return ""
    else:
        if mid+1 < len(lst) and lst[mid] > lst[mid+1] and lst[mid] > lst[mid -1]:
            return str(lst[mid]) + " " + Div(lst, low, mid-1) + Div(lst, mid+1, high)
        else:
            return Div(lst, low, mid-1) + Div(lst, mid + 1, high)

def peak(lst):
    if lst == []:
        return "list is empty"
    elif len(lst) in [1, 2]:
        return "No peak"
    else:
        return Div(lst, 0, len(lst))

print(peak([0, 5, 2, 9, 1, 10, 1]))
Capri answered 18/7, 2021 at 17:43 Comment(2)
Your answer is not valid Python code, please edit.Huron
@JariTurkia code is now fixed. Thank you for pointing it out. Im new to stackoverflow so did not know how to format code.Capri
L
-1

The idea is to use modified binary search.

If arr[mid+1]>arr[mid] then your peak ALWAYS exists on the right half.

If arr[mid-1]>arr[mid] then your peak ALWAYS exists on the left half. Because arr[i+1] have only two options, either bigger than arr[i] or smaller than arr[i-1]

I don't have java implementation but here is a python implementation.

def FindAPeak(arr, i, j):
    mid = (i+j)/2
    # if mid element is peak
    if (mid == len(arr)-1 or arr[mid] > arr[mid+1]) and (mid == 0 or arr[mid] > arr[mid-1]):
        return arr[mid]
    # when your peak exists in the right half
    if arr[mid] < arr[mid+1] and mid+1 < len(arr):
        return FindAPeak(arr, mid+1, j)
    # when your peak exists in the left half
    else:
        return FindAPeak(arr, i, mid-1)


In [31]: arr = [1,2,3,2,1]
    ...: FindAPeak(arr, 0, len(arr)-1)
    ...: 
Out[31]: 3


In [32]: 
    ...: arr = [1,2,3,4,5,6]
    ...: FindAPeak(arr, 0, len(arr)-1)
    ...: 
Out[32]: 6
Lepidus answered 27/10, 2017 at 22:9 Comment(1)
Not necessarily, there can still be a peak on the other side, so for finding all the peaks, the above algorithm is wrong. Eg: 5,4,3,2,1,0,5,2 There is a peak on both the sidesSemi

© 2022 - 2024 — McMap. All rights reserved.