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

题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为旋转。 输入一个递增的排序的数组的一个旋转,输出旋转数组的最小元素。

 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小元素为1.

这道题最直观的解法并不难,从头到尾遍历一次,我们就能找到最小的元素。这种思路的时间复杂度为O(n)。但是这个思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求。

我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都是大于等于后面子数组的元素(但当第一个数组元素等于中间数组元素等于最后数组的元素时就只能用顺序查找,即不能进行划分时)。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以利用二分查找来实现O(logn)的查找。本题给出的数组在一定程度上是排序的,因此我们可以试着用二分查找的思路来寻找这个最小的元素。

以前面的例子为例,我们先把第一个指针指向第0个元素,把第二个指针指向第4个元素,如图所示。位于两个指针中间(在数组的下标是2)的数字是5,它大于第一个指针指向的数字。因此中间数字5一定位于第一个递增字数组中,并且最小的数字一定位于它的后面。因此我们可以移动第一个指针让它指向数组的中间。

此时位于这两个指针中间的数字为1,它小于第二个指针指向的数字。因此这个中间数字为1一定位于第二个递增子数组中,并且最小的数字一定位于它的前面或者它自己就是最小的数字。因此我们可以移动第二个指针指向两个指针中间的元素即下标为3的元素。

此时两个指针的距离为1,表明第一个指针已经指向了第一个递增子数组的末尾,而第二个指针指向第二个递增子数组的开头。第二个子数组的第一个数字就是最小的数字,因此第二个指针指向的数字就是我们查找的结果。

  public int minInReversingList(int[] arr){  
        if(arr==null){  
            return -1;  
        }  
        int leftIndex = 0;  
        int rightIndex = arr.length -1;  
        int midIndex = leftIndex;  
        while(arr[leftIndex]>= arr[rightIndex]){  
            if(rightIndex - leftIndex <= 1){  
                midIndex = rightIndex;  
                break;  
            }  
            midIndex = (leftIndex+rightIndex)/2;  
            if(arr[leftIndex]== arr[rightIndex] && arr[midIndex]== arr[leftIndex]){  
                return MinInOrder(arr,leftIndex,rightIndex);  
            }  
            if(arr[midIndex] >= arr[leftIndex]){  
                leftIndex = midIndex;  
            }else if(arr[midIndex] < arr[rightIndex]){  
                rightIndex = midIndex;  
            }  
        }  
        return arr[midIndex];  
    }  
    public int MinInOrder(int[] arr,int leftIndex,int rightIndex){  
        int result = arr[leftIndex];  
        for(int i = leftIndex +1;i<rightIndex;i++){  
            if(result> arr[i]){  
                result = arr[i];  
            }  
        }  
        return result;  
    }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值