题目链接:LeetCode 剑指 Offer 11. 旋转数组的最小数字
题意:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
解题思路:
数组中找最小值,使用 O(n) 时间复杂度的算法没什么好说的,
题干给的是一个有序的数组,所以可以使用性能更优的二分查找来做
二分查找
只有中点和右端点比较大小,才能确定哪边属于连续递增数组
存在三种情况:
- 中间值比最右值大,最小元素肯定出现在右半部分,且肯定不是中间值 [3,4,5,1,2]
- 中间值比最右值小,最小元素肯定出现在左半部分,且可能是中间值 [1,2,3,4,5]
- 中间值和最右值相等,可能是 [1,1,1,2,1],也可能是 [1,1,1,0,1],所以只有缩小范围再试试
代码1:
func minArray(nums []int) int {
l, r := 0, len(nums)-1
for l < r {
mid := l + (r-l) >> 1
if nums[mid] > nums[r] {
l = mid+1
} else if nums[mid] < nums[r] {
r = mid
} else {
r--
}
}
return nums[l]
}
代码2:
func minArray(numbers []int) int {
if len(numbers) == 0 {
return - 1
}
// 直接进行二分操作,划分的区间是 [l,mid] [mid+1,r]
l := 0
r := len(numbers) - 1
for l < r {
mid := (l + r) / 2
if numbers[mid] > numbers[r] { //则最小值在右半部分
l = mid + 1
}else if numbers[mid] < numbers[r] { //最小值在左半部分
r = mid
}else{
r-- //如果相等,不确定在哪里,只能缩小范围进一步筛选
}
}
// 循环退出时,l == r
return numbers[l]
}
YZ 的思路:使用中间值 mid 与旋转后的数据的第一个元素进行比较,(需要判断的情况比较多,没有与最右边比较好理解)
标签:11,Offer,nums,mid,旋转,numbers,数组,else,LeetCode From: https://www.cnblogs.com/lxing-go/p/17547320.html