题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 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]] 。
示例
输入:numbers = [3,4,5,1,2]
输出:1
输入:numbers = [2,2,2,0,1]
输出:0
方法一:循环遍历
思想:因为原来的数组是升序排列,那么旋转过后,最右边元素会出现两种情况
(1)较大值,且最小值在其左边的数组中
(2)最小值,此时他它左边的元素都大于等于该元素,直接输出即可
class Solution {
public int minArray(int[] numbers) {
int iLength = numbers.length;
for(int i = iLength-1; i > 0; i--)
{
if(numbers[i] < numbers[i-1])
{
return numbers[i];
}
}
return numbers[0];
}
}
方法二:二分法
思想:
例如[4,5,6,7,1,2,3]
将一个数组按排序一分为二,分为左排序数组[4,5,6,7]和右排序数组[1,2,3]
其中左排序数组中任意元素>右排序数组中任意元素
按照二分法的思想,让nums[right]与nums[mid]进行比较,
将会出现三种情况
(1)nums[right]>nums[mid]
可知mid处于右排序数组中,因此最小值在mid左边或者就是mid,此时使right = mid
(2)nums[right]<nums[mid]
可知mid处于左排序数组中,因此最小值在mid右边,此时使left = mid + 1
(3)nums[right]=nums[mid]
此时mid状态位置,有可能在左排序数组,也有可能在右排序数组
示例一 [1,0,1,1,1],mid在右排序数组中。
示例二 [1,1,1,0,1],mid在左排序数组中
解决方法,为避免过程复杂,出现这种情况直接顺序遍历
class Solution {
public int minArray(int[] numbers) {
int iLeft,iRight,iMid;
iLeft = 0;
iRight = numbers.length - 1;
while(iLeft!=iRight)
{
iMid = (iLeft + iRight)/2;
if(numbers[iMid] == numbers[iRight])
{
return findMin(iRight,iLeft,numbers);
}
else if(numbers[iMid] > numbers[iRight])
{
iLeft = iMid + 1;
}
else
{
iRight = iMid;
}
}
return numbers[iRight];
}
public int findMin(int iRight,int iLeft,int[] nums)
{
int iMin= nums[iRight];
for(int i = iLeft ; i <= iRight;i++)
{
if(iMin > nums[i])
{
iMin = nums[i];
}
}
return iMin;
}
}
讨论:为什么不用left和mid元素做对比?
解答:因为原数组是升序的,因此用left与mid做对比不能确定mid是在左排序数组还是右排序数组
示例一 [5,1,2,3,4],mid在右排序数组中。
示例二 [2,3,4,5,1],mid在左排序数组中
如果大家还有好的方法可以在评论区一起讨论一下