旋转数组的最小数字【剑指】
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
二分法:
先进行一次比较,能够确定目标值在mid的那一侧,这里牵扯怎么选取一次target的问题,一般有以下两个选取原则:
1、如果有目标值target,那么直接让arr[mid] 和 target 比较即可。
*2、如果没有目标值,一般可以考虑左右端点。 *
这里我们把target看作是右端点,来进行分析,那就要分析以下三种情况,看是否可以达到上述的目标。
情况1,arr[mid] > target:4 5 6 1 2 3
说明[first ... mid] 都是 >= target 的,因为原始数组是非递减,所以可以确定答案为 [mid+1...last]区间,所以 first = mid + 1
情况2,arr[mid] < target:5 6 1 2 3 4
说明答案肯定不在[mid+1...last],但是arr[mid] 有可能是答案,所以答案在[first, mid]区间,所以last = mid;
情况3,arr[mid] == target:
如果是 1 0 1 1 1, arr[mid] = target = 1, 然答案在左边
如果是 1 1 1 0 1, arr[mid] = target = 1, 显然答案在右边
所以这种情况,不能确定答案在左边还是右边,那么就让last = last - 1;慢慢缩少区间,同时也不会错过答案。
复杂度分析
时间复杂度:二分,所以为O(longN), 但是如果是[1, 1, 1, 1],会退化到O(n)
空间复杂度:没有开辟额外空间,为O(1)
import java.util.ArrayList; public class Solution { public int minNumberInRotateArray(int [] array) { if(array==null) return 0; int n=array.length; int left=0,right=n-1; while(left<right){ int mid=(left+right)/2; if(array[mid]>array[right]){ left=mid+1; }else if(array[mid]<array[right]){ right=mid; }else{ right--; } } return array[left]; } }