「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战」
题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。
示例1
输入: [3,4,5,1,2]
输出: 1
示例2
输入: [2,2,2,0,1]
输出: 0
题解
初看题目很简单,一行代码解决
var minArray = function(numbers) { return Math.min(...numbers) };
细看一下原来是要求用二分法来求解。一行代码虽然简单,但是时间复杂度O(N);现在题目条件给出数组是排序的只是经过了一次反转。要利用数组在一定范围有序这一个特性。
话说二分法是真的要多思考理解啊,这题目都把二分玩出花来了。
二分法
数组是经过反转的数组;有什么条件分割数组呢?
假设现在数组左侧指针为:,右侧指针为:;并且最小值在区间
对于数组中 ,一定存在:
- 最小值右侧的元素,它们的值一定都小于等于
- 最小值左侧的元素,它们的值一定都大于等于
现在找区间的中间值
- 如果 。 落在最小值的左侧;最小值在之间
- 如果 遇到重复元素了,最小值在 区间
- 上述两种可能都不是最小元素只能在区间了
var minArray = function (numbers) {
let len = numbers.length
let left = 0
let right = len - 1
while (left < right) {
let mid = Math.floor(left + (right - left) / 2)
if (numbers[mid] > numbers[right]) {
left = mid + 1
} else if (numbers[mid] == numbers[right]) {
right = right - 1
} else {
right = mid
}
}
return numbers[left]
}
结语
作者水平有限,如有任何意见和建议欢迎评论区留言讨论