一【题目类别】
- 二分查找
二【题目难度】
- 中等
三【题目编号】
- 162.寻找峰值
四【题目描述】
- 峰值元素是指其值大于左右相邻值的元素。
- 给你一个输入数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
- 你可以假设 nums[-1] = nums[n] = -∞ 。
五【题目示例】
- 示例 1:
输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。 - 示例 2:
输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。
六【题目说明】
- 1 < = n u m s . l e n g t h < = 1000 1 <= nums.length <= 1000 1<=nums.length<=1000
- − 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 −231<=nums[i]<=231−1
- 对 于 所 有 有 效 的 i 都 有 n u m s [ i ] ! = n u m s [ i + 1 ] 对于所有有效的 i 都有 nums[i] != nums[i + 1] 对于所有有效的i都有nums[i]!=nums[i+1]
七【题目进阶】
- 你可以实现时间复杂度为 O ( l o g N ) O(logN) O(logN)的解决方案吗?
八【解题思路】
- 使用二分查找,首先要明确一点,正常的二分需要数组有序,这里是无序的所以我们可以仍沿用二分的思想,当中间值<右边的元素向右找,当中间值<左边的元素,向左找就可以归纳为那边大向哪边找,为什么呢?因为对于这个无序数组,nums[i] < nums[i+1],那么nums[i+2]有两种情况,一种是nums[i+2]<nums[i+1],那么nums[i+1]就是峰值,另一种是nums[i+2]>nums[i+1],那么根据题意需要向大的这边找,迭代下去就是结果
九【时间频度】
- 时间复杂度: O ( l o g N ) O(logN) O(logN)
十【代码实现】
- Java语言版
package BinarySearch;
public class p162_FindPeakElement {
public static void main(String[] args) {
int[] nums = {3, 4, 3, 2, 1};
int res = findPeakElement(nums);
System.out.println("res = " + res);
}
public static int findPeakElement(int[] nums) {
// 有两种情况需要特判,第一种情况,数组长度为1,直接返回0
if (nums.length == 1) {
return 0;
}
// 第二种情况,数组长度为2,比较两个元素,返回大的那个
if (nums.length == 2) {
return nums[0] > nums[1] ? nums[0] : nums[1];
}
// 接下来就是正常的二分算法
// 首先定义左右指针
int left = 0;
int right = nums.length - 1;
while (left <= right) {
// 这里还有两种情况需要特判,和上面的不同,这个判断的是while循环过程中的左右指针
// 第一种情况,左右指针指向了同一个元素,直接返回
if (left == right) {
return right;
}
// 第二种情况,左右指针只指向了两个元素,那么返回两个元素中大的下标
if (right - left == 1) {
return nums[left] > nums[right] ? left : right;
}
int mid = (left + right) / 2;
// 特判之后就是正常的二分查找
if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1]) { // 如果这个元素大于左右两个元素,那么就是我们要找的
return mid;
}
if (nums[mid] < nums[mid + 1]) { // 如果当前元素小于它右边的元素,那么说明要向右边找
left = mid + 1;
} else if (nums[mid] < nums[mid - 1]) { // 如果当前元素小于它左边的元素,那么说明要向左边找
right = mid - 1;
}
}
return -1;
}
}
- C语言版
#include<stdio.h>
#include<stdlib.h>
#include<io.h>
int findPeakElement(int* nums, int numsSize)
{
if (numsSize == 1)
{
return 0;
}
if (numsSize == 2)
{
return nums[0] > nums[1] ? 0 : 1;
}
int left = 0;
int right = numsSize - 1;
while (left <= right)
{
if (left == right)
{
return right;
}
if (right - left == 1)
{
return nums[left] > nums[right] ? left : right;
}
int mid = (left + right) / 2;
if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1])
{
return mid;
}
if (nums[mid] < nums[mid + 1])
{
left = mid + 1;
}
else if (nums[mid] < nums[mid - 1])
{
right = mid - 1;
}
}
return -1;
}
/*主函数省略*/
十一【提交结果】
-
Java语言版
-
C语言版