Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。
例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。
二、思路分析
- 寻找旋转数组中的最小值,首先可以考虑到的是遍历数组,如果当前元素比最小数值小,则替换最小数值为当前元素。
- 遍历的做法无法体现出旋转数组的性质,可以考虑从后向前遍历,如果当前元素比最小数值小则替换最小数值,如果当前元素比前一个元素大,则代表到达了旋转点,停止遍历。如果数组有一半数据是旋转的,那么遍历的元素个数可以降低一半。
- 第三种做法为二分查找,中间元素大于右边的数据,则更新l下标将其替换为mid+1,在右侧区间内搜索。mid+1是因为左侧为旋转数组+1后不影响继续遍历,如果中间元素大于左边的数据,则将r更新为mid,在左侧搜索,由于数组中有重复数据,不可以抛弃该数据,也就不能赋值为mid-1。
三、AC 代码
一次遍历
func minArray(numbers []int) int {
min := math.MaxInt32
for i := 0;i < len(numbers);i++ {
if min > numbers[i] {
min = numbers[i]
}
}
return min
}
尾部遍历
func minArray(numbers []int) int {
//尾指针
n := len(numbers)
min := numbers[n-1]
for i := n-1;i >= 0 ;i-- {
if min >= numbers[i] {
min = numbers[i]
} else{
return min
}
}
return min
}
二分查找
func minArray(numbers []int) int {
l,r := 0,len(numbers) - 1
for l < r {
mid := l +(r-l)/2
if numbers[mid] > numbers[r] {
l = mid + 1
}else if numbers[mid] < numbers[r] {
r = mid
}else{
r--
}
}
return numbers[l]
}
四、总结
一次遍历复杂度为O(n),尾部开始遍历复杂度不稳定,会根据遍历数组的情况不同发生改变。二分查找时间复杂度为O(log2n)。