代码实现:
方法一:遍历
int findPeakElement(int *nums, int numsSize) { if (numsSize == 1 || nums[0] > nums[1]) { return 0; } if (nums[numsSize - 1] > nums[numsSize - 2]) { return numsSize - 1; } int i; for (i = 1; i < numsSize; i++) { if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) { break; } } return i; }
方法二:二分法
数组的两端nums[-1] = nums[n] = -∞ 都是负无穷,因此数组无论是单调递增还是单调递减,又或者是成起伏状,数组中必定包含一个峰值。如下图所示:
因为数组中的峰值不止一个,我们找到任意一个即可。题目还告诉我们对于所有有效的i都有 nums[i] != nums[i + 1],即数组中的任意两个相邻数都不相等
使用二分查找,每次找出区间的中点mid,比较nums[mid]与nums[mid + 1]的大小关系来推断哪个区间内一定存在峰值,然后取一定存在峰值的区间。这样不断缩小区间范围,区间所剩下的最后一个数就是答案
- 如果
nums[mid] > nums[mid + 1]
,那么在[l, mid]
这个区间内一定存在一个峰值
- 如果
nums[mid] < nums[mid + 1]
,那么在[mid+1, r]
这个区间内一定存在一个峰值
int findPeakElement(int *nums, int numsSize) { int l = 0, r = numsSize - 1, mid; // 左闭右闭 while (l <= r) { mid = (l + r) >> 1; if ((mid == 0 || nums[mid] > nums[mid - 1]) && (mid == numsSize - 1 || nums[mid] > nums[mid + 1])) { // 找到了峰值 break; } if (nums[mid] > nums[mid + 1]) { // [l, mid - 1]这个区间一定存在一个峰值 r = mid - 1; } else { // [mid + 1, tail]这个区间一定存在一个峰值 l = mid + 1; } } return mid; }