1、题目
已知一个长度为
n
的数组,预先按照升序排列,经由
1
到
n
次
旋转 后,得到输入数组。例如,原数组
nums = [0,1,4,4,5,6,7]
在变化后可能得到:
- 若旋转
4
次,则可以得到[4,5,6,7,0,1,4]
- 若旋转
7
次,则可以得到[0,1,4,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]]
旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
。
给你一个可能存在 重复 元素值的数组 nums
,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
示例 1:
输入:nums = [1,3,5]
输出:1
示例 2:
输入:nums = [2,2,2,0,1]
输出:0
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
原来是一个升序排序的数组,并进行了1
至n
次旋转
进阶:
- 这道题是 寻找旋转排序数组中的最小值 的延伸题目。
- 允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
2、解题思路
(1)解决方案一:暴力破解;yyds;
从头到尾遍历,找到就返回true,找不到就拉倒(时间复杂度o(n),空间复杂度o(1))
(2)解决方案二:二分查找;(时间复杂度o(logn),空间复杂度o(1))
left,mid,right;
一样的,先left在最左边,right在最右边;然后中间值的index取两个中间;
left,mid,right;
一样的,先left在最左边,right在最右边;然后中间值的index取两个中间;
->如果中间值大于右边的元素,说明最小值在右边;挪动left
->否则说明最小值在左边,挪动right即可
->如果是相等的话,没有办法判断,直接挪动的话可以会错过,所以挪动一格接着循环判断
ps:这种为0的就是在原来不相等的情况下考虑一下重复可能会出现的特殊场景,然后进行逻辑补充
3、java代码
public int findMin(int[] nums) {
if(nums==null || nums.length==0) return 0;
int left = 0;
int right = nums.length - 1;
while (left < right) { //因为最后肯定是left=right,然后就是最小值
int mid=left+(right-left)/2;
if(nums[mid]>nums[right]){ //说明最小值在右边
left=mid+1;
}else if (nums[mid]<nums[right]){//说明最小值在左边
right=mid;//因为mid比right小,所以这里mid也可能是最小的
}else{ //如果相等的话说明可能在左边也可能在右边,直接挪动太大可能错过,所以把右边挪一格在进行循环判断
right--;
}
}
return nums[left];//最后肯定是left=right的,所以最上面循环用left<right
}