面试题11:旋转数组的最小数字
题目:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
方法:
对比取数组中的中间部分,start,mid和end,
循环(start<end)
①如果start和end只相差1(比较到了最后)
a. 如果end == A.length-1-loc,则为递增数列
b. 如果a不成立,则比较A[start]和A[end],更小的为最小值
② 如果A[start] == A[end],缩短数组 start++ end-- 且loc++(用于定位数组末尾,判断是否为递增数列)
③ 如果A[start]!= A[end],比较A[start]和A[mid],若A[start]<A[mid],则左边为递增数组,将start赋值为mid
④ 如果一直比对到start=end,则返回loc位置
案例:
eg: 5 6 7 8 1 2 3 4 (正常旋转数组)
①start=0,end=7,mid=3 A[0]<A[7] → start=3
②start=3, end=7, mid=5 A[3]>A[7] → end=5
③start=3, end=5, mid=4 A[3] >A[4] → end=4
④此时start+1=end 进入判断,end!== A.length-1-loc(loc此时为0),A[start]和A[end]中更小的为1
eg:1 1 1 1 0 1 1 1 (两端有重复值时,无法通过两边的大小来判断递增)
① start=0,end=7,mid=4 两端相等→ start=1, end=6,loc=1
② start=1,end=6,mid=4 两端相等→ start=2,end=5,loc=2
③ start=2,end=5,mid=4 两端相等→ start=3,end=4,loc=3
④ start=3,end=4,mid=4 此时start+1=end 进入判断,end != A.length-1-loc(loc此时为0),返回更小值,即0
eg: 0 1 2 3 4 5 6 (递增数组时,最小值为A[0])
① start=0,end=6,mid=3 A[0]<A[6] →start=3
② start=3, end=6,mid=4 A[3]<A[4] →start=4
③ start=4,end=6,mid=5 A[4]<A[5] → start=5
④ start=5,end=6,此时start+1=end 进入判断,end == A.length-1-loc(loc此时为0),返回loc位置,即A[0]
public class Q11 {
public static void main(String[] args) {
int[] A = new int[] {1,2};
System.out.println(findNum(A));
}
public static int findNum(int[] A) {
int left = 0;
int right = A.length-1;
int mid = 0;
int loc = 0;
while(left<right) {
mid = (left+right)/2;
System.out.printf("left:%d,right:%d,mid:%d\n", left,right,mid);
if(left+1==right) {
// 防止递增数列
if(right == A.length-1-loc) {
return A[loc];
}
if(A[left]<A[right]) {
return A[left];
}else {
return A[right];
}
}
// 两边相等 则缩小范围
if(A[left] == A[right]) {
left++;
right--;
loc = left;
}else {
// 两边不相等 再和中间的相比
if(A[left]<A[mid]) {
System.out.printf("A[%d]:%d < A[%d]:%d\n",left,A[left],mid,A[mid]);
left = mid;
}else if(A[left]>A[mid]) {
System.out.printf("A[%d]:%d > A[%d]:%d\n",left,A[left],mid,A[mid]);
right = mid;
}
}
}
return A[loc];
}
}