题目描述
解题思路
思路一:
这是一道二分查找的变形的题目。旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素。注意到实际上最小的元素就是两个子数组的分界线。本题目给出的数组一定程度上是排序的,因此我们试着用二分查找法寻找这个最小的元素。
设置两个指针low,high;low指向数组的开始位置,也就是第一个数组的开始位置,high指向数组的终止位置,也就是第二个数组的结束位置。
(1)如果没有发生旋转,也就是排序数组没有变,这时low指向的数小于high指向的数,数组的首元素就是最小的数,令mid=low;
(2)如果发生旋转,前面的数去了至少一个放在数组的后面,令mid=low+(high-low)/2;
a. 如果中间位置mid的数大于low指向的数,则mid在第一个数组中,让low指向mid所指向的数,low指向的依然是数组1的数;
b. 如果中间位置mid的数小于high所指向的位置,则mid在第二个数组中,high指向mid指向的数,high指向的依然是数组2的数;
c. 如果中间位置的数既等于low位置数,又等于high位置的数,这时候,不能确定移哪个指针,就必须采用顺序查找的方法来寻找最小数;
即:mid不是指向数组1的数,就是指向数组2的数,指向数组1的数,就让low移动到mid的位置,指向数组2就让high移动到mid的位置;直到high移动到数组1的结束的位置,low移动到数组2的开始的位置,此时low与high挨着,而且low所指向的数组2的起始位置中存放的就是最小数。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0)
return 0;
int low = 0;
int high = array.length - 1;
//旋转数组为排序数组本身的特例
int mid = low;
while(array[low]>= array[high]){
// 分界点
if(high - low == 1){
mid = high;
break;
}
mid = low + (high - low) / 2;
//考虑两侧数字和中间数字相同的特殊情况,采用顺序查找算法查找最小值
if(array[low]== array[high] && array[mid]== array[low]){
return MinInOrder(array,low,high);
}
// 中间元素位于前面的递增子数组
// 此时最小元素位于中间元素的后面
if(array[mid] >= array[low]){
low = mid;
// 中间元素位于后面的递增子数组
// 此时最小元素位于中间元素的前面
}else if(array[mid] <= array[high]){
high = mid;
}
}
return array[mid];
}
//顺序查找
private int MinInOrder(int[] array,int low,int high){
int result = array[low];
for(int i = low +1;i<high;i++){
if(result> array[i]){
result = array[i];
}
}
return result;
}
}
思路二:
采用二分法解答这个问题
mid = low + (high - low)/2
需要考虑三种情况:
(1)array[mid] > array[high]:出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1
(2)array[mid] == array[high]:出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边
还是右边,这时只好一个一个试 ,
high = high - 1
(3)array[mid] < array[high]:出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
边。因为右边必然都是递增的。
high = mid
注意这里有个坑:如果待查询的范围最后只剩两个数,那么mid 一定会指向下标靠前的数字比如 array = [4,6]
array[low] = 4 ;array[mid] = 4 ; array[high] = 6 ;
如果high = mid - 1,就会产生错误, 因此high = mid
但情形(1)中low = mid + 1就不会错误
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array == null || array.length == 0)
return 0;
int low=0;
int high=array.length-1;
while(low<high){
int mid=low+(high-low)/2;
if(array[mid]>array[high])
low=mid+1;
else if(array[mid]==array[high])
high=high-1;
else
high=mid;
}
return array[low];
}
}