852. 山脉数组的峰顶索引
这是我参与更文挑战的第 6 天,活动详情查看: 更文挑战
题目
来源:力扣(LeetCode)
符合下列属性的数组 arr 称为 山脉数组 :
-
arr.length >= 3
-
存在
i(0 < i < arr.length - 1)
使得:arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。
示例 1:
输入:arr = [0,1,0]
输出:1
示例 2:
输入:arr = [0,2,1,0]
输出:1
示例 3:
输入:arr = [0,10,5,2]
输出:1
示例 4:
输入:arr = [3,4,5,1]
输出:2
示例 5:
输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2
提示:
3 <= arr.length <= 104
0 <= arr[i] <= 106
- 题目数据保证
arr
是一个山脉数组
**进阶:**很容易想到时间复杂度 O(n)
的解决方案,你可以设计一个 O(log(n))
的解决方案吗?
问题分析
山脉数组的意思是,一个数组中有一个最大值,下标是i,那么i之前数组是递增的,i之后数组是递减的
进阶要求是设计一个 O(log(n))
的解决方案,看到 O(log(n))
,自然就要想到二分查找了
一次遍历
这是很常规的解法,就是遍历一次数组,找到第i个元素,满足arr[i]> arr[i-1] 并且arr[i] < arr[i+1],那么i就是要返回的结果了,代码就不写了
二分查找
计算 mid 时需要防止溢出,一般建议写成: mid = left + (right - left) / 2
我觉得写成mid = (left + right) >>> 1这样更好,无符号右移一位也能防止溢出
public class Solution {
public int peakIndexInMountainArray1(int[] arr) {
//从[1,arr.length - 2]中查找
int left = 1;
int right = arr.length - 2;
while (left <= right) {
int mid = (left + right) >>> 1;
if (arr[mid] < arr[mid - 1]) {
right = mid - 1;
} else if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
}
二分查找的思想是很简单,但是代码写起来还是很容易出错的,确实是思路很简单,细节是魔鬼
- 首先我定义的left = 1,right = arr.length - 2,这是因为根据题意,数组最少有三个数,而且峰顶不会是第0位或者最后一位。我这样定义也就意味这我要查找的区间是一个左右都闭合的区间[1,arr.length - 2]
- 因为左右都是闭合的区间,所以while循环中用的是小于等于,而不是小于。比如说数组中只有三个数{1,2,3},此时left=1,right=1,如果只用小于号,这种情况是进不了while循环的
- 因为左右都是闭合的区间,所以 right = mid - 1, left = mid + 1,而不是 right = mid , left = mid。就是mid是在闭合的区间内的,它已经被计算过一次了,下次就要把它去掉
所以也可以写成这样
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int left = 1;
int right = arr.length - 1;
while (left < right) {
int mid = (left + right) >>> 1;
if (arr[mid] < arr[mid - 1]) {
right = mid ;
} else if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
}
关于二分查找的细节可以看详解二分查找算法 www.cnblogs.com/kyoner/p/11…
leetcode也总结了二分查找的三个模板 leetcode-cn.com/leetbook/re… 可以看看