Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 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]] 。
示例
示例1:
输入: numbers = [3,4,5,1,2]
输出: 1
示例2:
输入: numbers = [2,2,2,0,1]
输出: 0
提示
- n == numbers.length
- 1 <= n <= 5000
- -5000 <= numbers[i] <= 5000
- numbers 原来是一个升序排序的数组,并进行了 1 至 n 次旋转
难度:简单
此题为简单题,兄弟们可以重拳出击!
记得这题最开始做的时候不是简单题目,现在降级了,不知道是题目简单了还是人刷题的人厉害了。
二、思路分析
众所周知,力扣上,简单题是真简单,中等题有些困难,困难题看不懂答案。
题目解析
- 一个非降序排列的数组中所有元素进行一定程度的旋转之后,找出数组中最小的元素。对于非降序的原数组,第一个元素是最小的,但是经过一定程度的旋转后,最小元素不知道被移动到哪里,找起来还是要费点功夫。
- 简单的方法,可以通过对数组进行一次遍历,并使用全局变量存储当前最小元素,在遍历时比较和更新最小值,遍历完成后全局变量就是最小元素。
- 如果数组长度过大,或时间性能有要求,则需要使用二分法来寻找最小元素
- 二分法最适宜的序列是有序序列,可以快速的判断并丢弃一半数据
- 旋转后的数组虽然整体不是有序的,但是也满足一定的规律,可以通过修改二分法判断条件来满足
- 对于旋转后非有序的数组,使用二分法获取中间位置元素时,有情况如下:
- 中间位置元素大于右端点时,说明最小元素一定在右半段,此时左端点移动为 mid+1
- 中间位置元素小于右端点时,说明最小元素在包含中间元素的左半段,此时右端点为 mid
- 中间位置元素等于右端点时,不能判断最小元素在哪里,但是因为 mid 元素等于右端点,因此可以舍去右端点的值,此时最小值不会丢失,且 mid 可以继续进行二分
- 循环至 l=r 时结束,当前即最小值
- 如果数组旋转后元素位置没有变,则依然满足上述方法,此时一直是右端点左移
三、AC 代码
二分法查找最小数字
- 二分法查找,考虑mid位置
public int minArray(int[] numbers) {
int l = 0, r = numbers.length-1;
while(l < r){
int 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[r];
}
四、总结
知识点
- 二分法的边界问题
- 两个端点何时等于 mid,何时等于 mid+/-1,需要根据实际情况判断
最后
阳春三月,算法刷起来!LeetCode 剑指 Offer。
简单题,不需要考虑太多,开干就是了。