📜  查找峰元素

📅  最后修改于: 2021-05-04 14:42:40             🧑  作者: Mango

给定一个整数数组。在其中找到一个峰元素。如果数组元素不小于其邻居,则它是一个峰。对于角落元素,我们只需要考虑一个邻居。

例子:

Input: array[]= {5, 10, 20, 15}
Output: 20
The element 20 has neighbours 10 and 15,
both of them are less than 20.

Input: array[] = {10, 20, 15, 2, 23, 90, 67}
Output: 20 or 90
The element 20 has neighbours 10 and 15, 
both of them are less than 20, similarly 90 has neighbous 23 and 67.

跟踪一些极端情况可以更好地解决这个问题。

  1. 如果输入数组严格按升序排序,则最后一个元素始终是峰值元素。例如,50是{10,20,30,40,50}中的峰值元素。
  2. 如果输入数组按严格降序排序,则第一个元素始终是峰元素。 100是{100,80,60,50,20}中的峰值元素。
  3. 如果输入数组的所有元素都相同,则每个元素都是峰值元素。

从上面的示例可以清楚地看到,输入数组中始终存在一个峰值元素。

天真的方法:可以遍历数组,并且可以返回其邻居小于该元素的元素。
算法:

  1. 如果在数组中,第一个元素大于第二个元素或最后一个元素大于倒数第二个元素,则打印相应的元素并终止程序。
  2. 否则,将数组从第二个索引遍历到第二个最后一个索引
  3. 如果对于元素array [i] ,它大于它的邻居,即array [i]> array [i-1]和array [i]> array [i + 1] ,则打印该元素并终止。
C++
// A C++ program to find a peak element
#include 
using namespace std;
 
// Find the peak element in the array
int findPeak(int arr[], int n)
{
    // first or last element is peak element
    if (n == 1)
      return 0;
    if (arr[0] >= arr[1])
        return 0;
    if (arr[n - 1] >= arr[n - 2])
        return n - 1;
 
    // check for every other element
    for (int i = 1; i < n - 1; i++) {
 
        // check if the neighbors are smaller
        if (arr[i] >= arr[i - 1] && arr[i] >= arr[i + 1])
            return i;
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Index of a peak point is "
         << findPeak(arr, n);
    return 0;
}
 
// This code is contributed by Arnab Kundu


Java
// A Java program to find a peak element
import java.util.*;
 
class GFG{
 
// Find the peak element in the array
static int findPeak(int arr[], int n)
{
     
    // First or last element is peak element
    if (n == 1)
      return 0;
    if (arr[0] >= arr[1])
        return 0;
    if (arr[n - 1] >= arr[n - 2])
        return n - 1;
 
    // Check for every other element
    for(int i = 1; i < n - 1; i++)
    {
         
        // Check if the neighbors are smaller
        if (arr[i] >= arr[i - 1] &&
            arr[i] >= arr[i + 1])
            return i;
    }
    return 0;
}
 
// Driver Code
public static void main(String[] args)
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = arr.length;
     
    System.out.print("Index of a peak point is " +
                     findPeak(arr, n));
}
}
 
// This code is contributed by Princi Singh


Python3
# A Python3 program to find a peak element
 
# Find the peak element in the array
def findPeak(arr, n) :
 
    # first or last element is peak element
    if (n == 1) :
      return 0
    if (arr[0] >= arr[1]) :
        return 0
    if (arr[n - 1] >= arr[n - 2]) :
        return n - 1
  
    # check for every other element
    for i in range(1, n - 1) :
  
        # check if the neighbors are smaller
        if (arr[i] >= arr[i - 1] and arr[i] >= arr[i + 1]) :
            return i
             
# Driver code.
arr = [ 1, 3, 20, 4, 1, 0 ]
n = len(arr)
print("Index of a peak point is", findPeak(arr, n))
 
# This code is contributed by divyeshrabadiya07


C#
// A C# program to find a peak element
using System;
 
public class GFG{
 
// Find the peak element in the array
static int findPeak(int []arr, int n)
{
     
    // First or last element is peak element
    if (n == 1)
      return 0;
    if (arr[0] >= arr[1])
        return 0;
    if (arr[n - 1] >= arr[n - 2])
        return n - 1;
 
    // Check for every other element
    for(int i = 1; i < n - 1; i++)
    {
         
        // Check if the neighbors are smaller
        if (arr[i] >= arr[i - 1] &&
            arr[i] >= arr[i + 1])
            return i;
    }
    return 0;
}
 
// Driver Code
public static void Main(String[] args)
{
    int []arr = { 1, 3, 20, 4, 1, 0 };
    int n = arr.Length;
     
    Console.Write("Index of a peak point is " +
                     findPeak(arr, n));
}
}
 
  
 
// This code is contributed by 29AjayKumar


Javascript


C++
// A C++ program to find a peak element
// using divide and conquer
#include 
using namespace std;
 
// A binary search based function
// that returns index of a peak element
int findPeakUtil(int arr[], int low,
                 int high, int n)
{
    // Find index of middle element
    // (low + high)/2
    int mid = low + (high - low) / 2;
 
    // Compare middle element with its
    // neighbours (if neighbours exist)
    if ((mid == 0 || arr[mid - 1] <= arr[mid]) &&
        (mid == n - 1 || arr[mid + 1] <= arr[mid]))
        return mid;
 
    // If middle element is not peak and its
    // left neighbour is greater than it,
    // then left half must have a peak element
    else if (mid > 0 && arr[mid - 1] > arr[mid])
        return findPeakUtil(arr, low, (mid - 1), n);
 
    // If middle element is not peak and its
    // right neighbour is greater than it,
    // then right half must have a peak element
    else
        return findPeakUtil(
            arr, (mid + 1), high, n);
}
 
// A wrapper over recursive function findPeakUtil()
int findPeak(int arr[], int n)
{
    return findPeakUtil(arr, 0, n - 1, n);
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Index of a peak point is "
         << findPeak(arr, n);
    return 0;
}
 
// This code is contributed by rathbhupendra


C
// C program to find a peak
// element using divide and conquer
#include 
 
// A binary search based function that
// returns index of a peak element
int findPeakUtil(
    int arr[], int low, int high, int n)
{
    // Find index of middle element
    // (low + high)/2
    int mid = low + (high - low) / 2;
 
    // Compare middle element with
    // its neighbours (if neighbours exist)
    if ((mid == 0 || arr[mid - 1] <= arr[mid]) && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
        return mid;
 
    // If middle element is not peak and
    // its left neighbour is greater
    // than it, then left half must have a peak element
    else if (mid > 0 && arr[mid - 1] > arr[mid])
        return findPeakUtil(arr, low, (mid - 1), n);
 
    // If middle element is not peak and
    // its right neighbour is greater
    // than it, then right half must have a peak element
    else
        return findPeakUtil(arr, (mid + 1), high, n);
}
 
// A wrapper over recursive function findPeakUtil()
int findPeak(int arr[], int n)
{
    return findPeakUtil(arr, 0, n - 1, n);
}
 
/* Driver program to check above functions */
int main()
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    printf(
        "Index of a peak point is %d", findPeak(arr, n));
    return 0;
}


Java
// A Java program to find a peak
// element using divide and conquer
import java.util.*;
import java.lang.*;
import java.io.*;
 
class PeakElement {
    // A binary search based function
    // that returns index of a peak element
    static int findPeakUtil(
        int arr[], int low, int high, int n)
    {
        // Find index of middle element
        // (low + high)/2
        int mid = low + (high - low) / 2;
 
        // Compare middle element with its
        // neighbours (if neighbours exist)
        if ((mid == 0 || arr[mid - 1] <= arr[mid])
            && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
            return mid;
 
        // If middle element is not peak
        // and its left neighbor is
        // greater than it, then left half
        // must have a peak element
        else if (mid > 0 && arr[mid - 1] > arr[mid])
            return findPeakUtil(arr, low, (mid - 1), n);
 
        // If middle element is not peak
        // and its right neighbor
        // is greater than it, then right
        // half must have a peak
        // element
        else
            return findPeakUtil(
                arr, (mid + 1), high, n);
    }
 
    // A wrapper over recursive function
    // findPeakUtil()
    static int findPeak(int arr[], int n)
    {
        return findPeakUtil(arr, 0, n - 1, n);
    }
 
    // Driver method
    public static void main(String[] args)
    {
        int arr[] = { 1, 3, 20, 4, 1, 0 };
        int n = arr.length;
        System.out.println(
            "Index of a peak point is " + findPeak(arr, n));
    }
}


Python3
# A python3 program to find a peak
# element element using divide and conquer
 
# A binary search based function
# that returns index of a peak element
def findPeakUtil(arr, low, high, n):
     
     # Find index of middle element
     # (low + high)/2
     mid = low + (high - low)/2
     mid = int(mid)
     
    # Compare middle element with its
    # neighbours (if neighbours exist)
    if ((mid == 0 or arr[mid - 1] <= arr[mid]) and
        (mid == n - 1 or arr[mid + 1] <= arr[mid])):
        return mid
 
 
    # If middle element is not peak and
    # its left neighbour is greater
    # than it, then left half must
    # have a peak element
    elif (mid > 0 and arr[mid - 1] > arr[mid]):
        return findPeakUtil(arr, low, (mid - 1), n)
 
    # If middle element is not peak and
    # its right neighbour is greater
    # than it, then right half must
    # have a peak element
    else:
        return findPeakUtil(arr, (mid + 1), high, n)
 
 
# A wrapper over recursive
# function findPeakUtil()
def findPeak(arr, n):
 
    return findPeakUtil(arr, 0, n - 1, n)
 
 
# Driver code
arr = [1, 3, 20, 4, 1, 0]
n = len(arr)
print("Index of a peak point is", findPeak(arr, n))
     
# This code is contributed by
# Smitha Dinesh Semwal


C#
// A C# program to find
// a peak element element
// using divide and conquer
using System;
 
class GFG {
 
    // A binary search based
    // function that returns
    // index of a peak element
    static int findPeakUtil(int[] arr, int low,
                            int high, int n)
    {
        // Find index of
        // middle element
        int mid = low + (high - low) / 2;
 
        // Compare middle element with
        // its neighbours (if neighbours
        // exist)
        if ((mid == 0 || arr[mid - 1] <= arr[mid]) && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
            return mid;
 
        // If middle element is not
        // peak and its left neighbor
        // is greater than it, then
        // left half must have a
        // peak element
        else if (mid > 0 && arr[mid - 1] > arr[mid])
            return findPeakUtil(arr, low,
                                (mid - 1), n);
 
        // If middle element is not
        // peak and its right neighbor
        // is greater than it, then
        // right half must have a peak
        // element
        else
            return findPeakUtil(arr, (mid + 1),
                                high, n);
    }
 
    // A wrapper over recursive
    // function findPeakUtil()
    static int findPeak(int[] arr,
                        int n)
    {
        return findPeakUtil(arr, 0,
                            n - 1, n);
    }
 
    // Driver Code
    static public void Main()
    {
        int[] arr = { 1, 3, 20,
                      4, 1, 0 };
        int n = arr.Length;
        Console.WriteLine("Index of a peak "
                          + "point is " + findPeak(arr, n));
    }
}
 
// This code is contributed by ajit


PHP
 0 &&
             $arr[$mid - 1] > $arr[$mid])
        return findPeakUtil($arr, $low,
                           ($mid - 1), $n);
 
    // If middle element is not peak
    // and its right neighbour is
    // greater than it, then right
    // half must have a peak element
    else return(findPeakUtil($arr, ($mid + 1),
                             $high, $n));
}
 
// A wrapper over recursive
// function findPeakUtil()
function findPeak($arr, $n)
{
    return floor(findPeakUtil($arr, 0,
                              $n - 1, $n));
}
 
// Driver Code
$arr = array(1, 3, 20, 4, 1, 0);
$n = sizeof($arr);
echo "Index of a peak point is ",
              findPeak($arr, $n);
 
// This code is contributed by ajit
?>


Javascript


输出:

Index of a peak point is 2

复杂度分析:

  • 时间复杂度: O(n)。
    需要进行一次遍历,因此时间复杂度为O(n)
  • 空间复杂度: O(1)。
    不需要额外的空间,因此空间复杂度是恒定的

高效方法:可以使用分而治之找到O(Logn)时间的峰值。这个想法是基于二进制搜索技术来检查中间元素是否是峰值元素。如果中间元素不是峰值元素,则检查右侧的元素是否大于中间元素,然后在右侧始终存在一个峰值元素。如果左侧的元素大于中间的元素,则左侧总是有一个峰值元素。形成递归,峰值元素可以在log n次内找到。

算法:

  1. 创建两个变量lr ,初始化l = 0r = n-1
  2. 重复以下步骤,直到l <= r ,下限小于上限
  3. 检查中间值或索引mid =(l + r)/ 2是否为峰值元素,如果是,则打印该元素并终止。
  4. 否则,如果中间元素左侧的元素较大,则检查左侧的峰值元素,即更新r = mid – 1
  5. 否则,如果中间元素右侧的元素较大,则检查右侧的峰元素,即更新l = mid + 1

C++

// A C++ program to find a peak element
// using divide and conquer
#include 
using namespace std;
 
// A binary search based function
// that returns index of a peak element
int findPeakUtil(int arr[], int low,
                 int high, int n)
{
    // Find index of middle element
    // (low + high)/2
    int mid = low + (high - low) / 2;
 
    // Compare middle element with its
    // neighbours (if neighbours exist)
    if ((mid == 0 || arr[mid - 1] <= arr[mid]) &&
        (mid == n - 1 || arr[mid + 1] <= arr[mid]))
        return mid;
 
    // If middle element is not peak and its
    // left neighbour is greater than it,
    // then left half must have a peak element
    else if (mid > 0 && arr[mid - 1] > arr[mid])
        return findPeakUtil(arr, low, (mid - 1), n);
 
    // If middle element is not peak and its
    // right neighbour is greater than it,
    // then right half must have a peak element
    else
        return findPeakUtil(
            arr, (mid + 1), high, n);
}
 
// A wrapper over recursive function findPeakUtil()
int findPeak(int arr[], int n)
{
    return findPeakUtil(arr, 0, n - 1, n);
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Index of a peak point is "
         << findPeak(arr, n);
    return 0;
}
 
// This code is contributed by rathbhupendra

C

// C program to find a peak
// element using divide and conquer
#include 
 
// A binary search based function that
// returns index of a peak element
int findPeakUtil(
    int arr[], int low, int high, int n)
{
    // Find index of middle element
    // (low + high)/2
    int mid = low + (high - low) / 2;
 
    // Compare middle element with
    // its neighbours (if neighbours exist)
    if ((mid == 0 || arr[mid - 1] <= arr[mid]) && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
        return mid;
 
    // If middle element is not peak and
    // its left neighbour is greater
    // than it, then left half must have a peak element
    else if (mid > 0 && arr[mid - 1] > arr[mid])
        return findPeakUtil(arr, low, (mid - 1), n);
 
    // If middle element is not peak and
    // its right neighbour is greater
    // than it, then right half must have a peak element
    else
        return findPeakUtil(arr, (mid + 1), high, n);
}
 
// A wrapper over recursive function findPeakUtil()
int findPeak(int arr[], int n)
{
    return findPeakUtil(arr, 0, n - 1, n);
}
 
/* Driver program to check above functions */
int main()
{
    int arr[] = { 1, 3, 20, 4, 1, 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    printf(
        "Index of a peak point is %d", findPeak(arr, n));
    return 0;
}

Java

// A Java program to find a peak
// element using divide and conquer
import java.util.*;
import java.lang.*;
import java.io.*;
 
class PeakElement {
    // A binary search based function
    // that returns index of a peak element
    static int findPeakUtil(
        int arr[], int low, int high, int n)
    {
        // Find index of middle element
        // (low + high)/2
        int mid = low + (high - low) / 2;
 
        // Compare middle element with its
        // neighbours (if neighbours exist)
        if ((mid == 0 || arr[mid - 1] <= arr[mid])
            && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
            return mid;
 
        // If middle element is not peak
        // and its left neighbor is
        // greater than it, then left half
        // must have a peak element
        else if (mid > 0 && arr[mid - 1] > arr[mid])
            return findPeakUtil(arr, low, (mid - 1), n);
 
        // If middle element is not peak
        // and its right neighbor
        // is greater than it, then right
        // half must have a peak
        // element
        else
            return findPeakUtil(
                arr, (mid + 1), high, n);
    }
 
    // A wrapper over recursive function
    // findPeakUtil()
    static int findPeak(int arr[], int n)
    {
        return findPeakUtil(arr, 0, n - 1, n);
    }
 
    // Driver method
    public static void main(String[] args)
    {
        int arr[] = { 1, 3, 20, 4, 1, 0 };
        int n = arr.length;
        System.out.println(
            "Index of a peak point is " + findPeak(arr, n));
    }
}

Python3

# A python3 program to find a peak
# element element using divide and conquer
 
# A binary search based function
# that returns index of a peak element
def findPeakUtil(arr, low, high, n):
     
     # Find index of middle element
     # (low + high)/2
     mid = low + (high - low)/2
     mid = int(mid)
     
    # Compare middle element with its
    # neighbours (if neighbours exist)
    if ((mid == 0 or arr[mid - 1] <= arr[mid]) and
        (mid == n - 1 or arr[mid + 1] <= arr[mid])):
        return mid
 
 
    # If middle element is not peak and
    # its left neighbour is greater
    # than it, then left half must
    # have a peak element
    elif (mid > 0 and arr[mid - 1] > arr[mid]):
        return findPeakUtil(arr, low, (mid - 1), n)
 
    # If middle element is not peak and
    # its right neighbour is greater
    # than it, then right half must
    # have a peak element
    else:
        return findPeakUtil(arr, (mid + 1), high, n)
 
 
# A wrapper over recursive
# function findPeakUtil()
def findPeak(arr, n):
 
    return findPeakUtil(arr, 0, n - 1, n)
 
 
# Driver code
arr = [1, 3, 20, 4, 1, 0]
n = len(arr)
print("Index of a peak point is", findPeak(arr, n))
     
# This code is contributed by
# Smitha Dinesh Semwal

C#

// A C# program to find
// a peak element element
// using divide and conquer
using System;
 
class GFG {
 
    // A binary search based
    // function that returns
    // index of a peak element
    static int findPeakUtil(int[] arr, int low,
                            int high, int n)
    {
        // Find index of
        // middle element
        int mid = low + (high - low) / 2;
 
        // Compare middle element with
        // its neighbours (if neighbours
        // exist)
        if ((mid == 0 || arr[mid - 1] <= arr[mid]) && (mid == n - 1 || arr[mid + 1] <= arr[mid]))
            return mid;
 
        // If middle element is not
        // peak and its left neighbor
        // is greater than it, then
        // left half must have a
        // peak element
        else if (mid > 0 && arr[mid - 1] > arr[mid])
            return findPeakUtil(arr, low,
                                (mid - 1), n);
 
        // If middle element is not
        // peak and its right neighbor
        // is greater than it, then
        // right half must have a peak
        // element
        else
            return findPeakUtil(arr, (mid + 1),
                                high, n);
    }
 
    // A wrapper over recursive
    // function findPeakUtil()
    static int findPeak(int[] arr,
                        int n)
    {
        return findPeakUtil(arr, 0,
                            n - 1, n);
    }
 
    // Driver Code
    static public void Main()
    {
        int[] arr = { 1, 3, 20,
                      4, 1, 0 };
        int n = arr.Length;
        Console.WriteLine("Index of a peak "
                          + "point is " + findPeak(arr, n));
    }
}
 
// This code is contributed by ajit

的PHP

 0 &&
             $arr[$mid - 1] > $arr[$mid])
        return findPeakUtil($arr, $low,
                           ($mid - 1), $n);
 
    // If middle element is not peak
    // and its right neighbour is
    // greater than it, then right
    // half must have a peak element
    else return(findPeakUtil($arr, ($mid + 1),
                             $high, $n));
}
 
// A wrapper over recursive
// function findPeakUtil()
function findPeak($arr, $n)
{
    return floor(findPeakUtil($arr, 0,
                              $n - 1, $n));
}
 
// Driver Code
$arr = array(1, 3, 20, 4, 1, 0);
$n = sizeof($arr);
echo "Index of a peak point is ",
              findPeak($arr, $n);
 
// This code is contributed by ajit
?>

Java脚本


输出:

Index of a peak point is 2

复杂性分析:

  • 时间复杂度: O(Logn)。
    其中n是输入数组中元素的数量。在每一步中,我们的搜索将变成一半。因此可以将其与二进制搜索进行比较,因此时间复杂度为O(log n)
  • 空间复杂度: O(1)。
    不需要额外的空间,因此空间复杂度是恒定的。

锻炼:
考虑以下峰元素的修改定义。如果数组元素大于其邻居元素,则它是一个峰。注意,数组可能不包含具有此修改后定义的峰元素。
参考:
http://courses.csail.mit.edu/6.006/spring11/lectures/lec02.pdf
http://www.youtube.com/watch?v=HtSuA80QTyo

询问:亚马逊