山脉数组的峰顶索引 --- 旋转数组类似
符合下列属性的数组 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)) 的解决方案吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/peak-index-in-a-mountain-array
解题思路
根据题意可以知道是在一个数组中找最大值的下标。这样就限制了尽量不要将数组进行排序之后,找最大值,因为这样如果要找到原来数组的最大值的下表,还需要在原来的数组中查找。因此我们也可以很好的想到,使用一个临时变量,用来存储最大值的,包括下表,然后遍历的时候判断每个数组的元素和临时变量中的元素,如果大于临时变量中的值,则更换临时变量的值,如果不是则直接不变。如果想要在快速一点,我们使用双指针进行解决。双指针的驱动条件是:头尾指针元素的判断,再根据大小移动,即假设x为头,y为尾,判断arr[x]和arr[y]的大小。
代码
func peakIndexInMountainArray(arr []int) int {
x,y := 0,len(arr)-1
for x < y {
if arr[x] > arr[y] {
y--
}else if arr[x] <= arr[y] {
x++
}
}
return x
}
结果是对的。
这里并没真正的利用上双指针,因为使用双指针的驱动条件是中间数与头尾指针的判断。但是也有一种情况是根据中间数和中间数的下一位进行判断的,从而驱动头尾双指针。这种情况是一个数两边的单调性不同。
就好比如这道题。假设a为最大数的下标。如果i<a,则arr[i] < arr[i+1]。如果i>a,则arr[i]>arr[i+1]。因此我们就可以使用arr[mid]与arr[mid+1]进行判断,这里的mid是头尾指针的中间值,如果arr[mid] < arr[mid+1],则说明mid之后是单调递减的,后面不可能存在最大值,此时下标可以为mid,并且右指针就要改为right--。如果arr[mid]>arr[mid+1],则mid之后是先单调递增到单调递减,这里一定会存在最大值,左指针就要改为mid+1。以此循环下去,直到头尾指针相等,则直接返回其中一个即可。
代码
func peakIndexInMountainArray(arr []int) int {
x,y := 0,len(arr)-1
for x < y {
mid := (x+y) / 2
if arr[mid] >= arr[mid+1] {
y = mid
}else if arr[mid] < arr[mid+1] {
x = mid + 1
}
}
return x
}