题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
看到题意,其实十分疑惑,即使是旋转的数组,只要顺序查找不就行了吗?毕竟是线性的数据啊。但考虑到时间复杂度是n(n),觉得可能没有那么简单,但是即使是非递减,没不一定是递增的序列啊。所以这里出现了疑惑。后面在原本线性查找的方式上,想到了使用快排排序然后取第一个就可,时间复杂度在原本的基础上变为了log2n。但是如果要求效率高于线性查找,同时又不改变数组原有顺序呢?
这时,可能就需要根据原本的旋转数组这个特殊的结构进行分析了。非递减,可能是严格递增的也可能是存在相等的递增,或者不是一个有序的序列。但是通过选择点,进行旋转后,分成了两部分,选择点的前面可能递增也可能递减。通过二分查找法,逐步缩小范围来查找。
这里自己发现了一个图文结合描述很清楚的解释:
旋转数组
上代码:
/**
* 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
* 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
* 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
* NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
*/
public class Offer_05_minNumberInRotateArray {
public static void main(String[] args) {
int[] array = new int[]{6501,6828,6963,7036,7422,7674,8146,8468,8704,8717,9170,9359,9719,9895,9896,9913,9962,154,
293,334,492,1323,1479,1539,1727,1870,1943,2383,2392,2996,3282,3812,3903,4465,4605,4665,4772,4828,5142,
5437,5448,5668,5706,5725,6300,6335};
System.out.println(minNumInRotateArray3(array));
}
//第一种方法,线性查找法,直接按顺序查找,时间复杂度n(n),空间复杂度n(1)
// 牛客网:运行时间:416ms
//占用内存:28820k
public static int minNumberInRotateArray(int [] array) {
if (array.length == 0){
return 0;
}
int min = array[0];
for(int i = 0;i<array.length;i++){
if(min > array[i]){
min = array[i];
}
}
return min;
}
//第二种方法,使用Array中的排序(快排),时间复杂的n(log2n)
public static int minNumInRotateArray2(int[] array){
Arrays.sort(array);
return array[0];
}
//第三种,
public static int minNumInRotateArray3(int[] array){
if(array.length == 0){
return 0;
}
int high = array.length -1;
int low = 0;
int mid ;
while (low < high){
if(array[low] < array[high]){
return array[low];
}
mid = (high + low)/2;
if(array[low] < array[mid]){
low = mid +1;
}else if(array[mid] < array[high]){
high = mid;
}
else
low++;
}
return array[low];
}
}