剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
- 方法1 :暴力解法,用for遍历所有元素,找出最小值,此方法没有用到题目给的递增排序的条件
//暴力解法
public static int minArray(int[] numbers){
int min=Integer.MAX_VALUE;
for (int i:numbers){
if(min>=i){
min=i;
}
}
return min;
}
- 方法2:用到"递增排序的数组的一个旋转"的条件,使用两个指针i(0~numbers.length-2)和j(i+1),对数组进行一次遍历,
- 因为他原先是递增数组,即numbers[i]恒小于numbers[j],但经过一次旋转,他必定会有一次numbers[i]大于numbers[j],也就是拐点
- 如果发现有numbers[i]大于numbers[j]则返回j,否则返回0;
//稍作优化双指针对比
public static int minArray(int[] numders){
int i=0,j=1,min=0;
while (j<numders.length){
if(numders[i]>numders[j])min=j;
j++;
i++;
}
return numders[min];
}
- 方法3:在方法2的基础下再次优化,只用一个指针z,倒叙遍历数组,则遍历情况应该单调递减,如果出现拐点,也就是后一个元素比前一个小,则是我们要找的最小值
//数组倒序
public static int minArray(int[] numbers) {
int min= Integer.MAX_VALUE,z=numbers.length;
while(min>=numbers[--z]){
min=numbers[z];
if(z==0)break;
}
return min;
}
- 方法4:二分法,通过二分搜索思想,创建前指针i和后指针j,以及他们相加除二m,通过j元素和m元素比较
- 因为是递增数组,所以当numbers[m]>numbers[j]则说明min在m+1~j之间;
- 如果当numbers[m]<numbers[j]则说明min在i~m之间;
- 当numbers[m]==numbers[j]时,j--即可;
//二分法
public static int minArray4(int[] numbers){
int i=0,j=numbers.length-1;
while (i<j){
int m=(i+j)/2;
if(numbers[m]>numbers[j])i=m+1;
else if(numbers[m]<numbers[j])j=m;
else j--;
}
return numbers[j];
}