剑指offer:旋转数组的最小数字

题目

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解题思路

这是一道二分查找的变形题,这里的旋转数组是两个有序的递增子数组拼接起来的,且前面一个子数组里的任意一个数都大于后面子数组中的数。而要找的最小值就是前后两个子数组的分界点。

 

用三个指针begin、end、middle分别指向数组的首尾和中间元素

1)若middle元素大于或者等于begin元素说明中间元素位于前半部分数组中,最小元素在后半部分的数组中,则将begin设为middle继续在后半部分中寻找

2)若middle元素小于或者等于end元素说明中间元素位于后半部分数组中,最小部分在前半部分或者中间元素就是最小元素,则将end设为middle继续在前半部分中寻找

这样不断缩小范围,直到最后begin和end会成为相邻的元素,此时end所指元素就是最小值

 

特殊情况:

1)0个元素旋转到后半部分,那么此时旋转数组就是一个非递减数组,最小值就是第一个元素,也就是为什么初始middle设为0的原因

2)当begin、end、middle三个元素都相等时,无法判断中间元素在前半部分数组还是后半部分数组,只能遍历数组寻找最小值

例如1,1,1,0,1和1,0,1,1,1都可以看成是0,1,1,1,1的翻转数组

 

代码

 1     public int minNumberInRotateArray(int [] array) {
 2         if(array.length==0)
 3             return 0;
 4         int begin = 0,end = array.length-1,middle = 0;
 5         while(array[begin]>=array[end]){
 6             if((end-begin)==1){
 7                 middle = end;
 8                 break;
 9             }
10             middle = (begin+end)/2;
11             if(array[begin]==array[middle]&&array[middle]==array[end]){
12                 return minInOrder(array,begin,end);
13             }
14             if(array[middle]>=array[begin]){
15                 begin = middle;
16             }else if(array[middle]<=array[end]){
17                 end = middle;
18             }
19             
20         }
21         return array[middle];
22     }
23     
24     private int minInOrder(int[] array,int begin,int end){
25         int min = array[begin];
26         for(int i = begin+1;i<end;i++){
27             if(min>array[i]){
28                 min = array[i];
29             }
30         }
31         return min;
32     }

 

posted @ 2019-06-22 16:52  huanglf714  阅读(170)  评论(0编辑  收藏  举报