面试题11:旋转数组的最小数字

题目

该系列文章题目和思路均参考自:《剑指Offer》

解法

思路1:求解一个数组中的最小元素,很容易想到进行遍历即可,时间复杂度为O(n)。但这种方式没有用到题目中给的数组旋转的特点。

思路2:类似于二分查找法。使用两个指针分别指向数组头(p1)和尾(p2),然后查找到两个指针中间的元素,如果中间的元素位于前面递增的子数组中,那么它应该大于等于p1指向的元素,那么数组中最小的元素在后半部分。这样就可以将p1移动到中间元素的位置,在进行查找。

类似的如果中间的元素位于后面的递增子数组中,那么它应该小于或等于p2指向的元素,此时数组中最小的元素应该位于前半部分。这样就可以将p2移动到中间元素的位置在进行查找。

根据以上思路,p1指针总是指向前面递增子数组的元素,p2指针总是指向后面递增子数组的元素,最后p1将指向前面递增子数组的最后一个元素,p2将指向后面递增子数组的第一个元素。p1和p2即相邻,此时p2指向的元素即为数组中最小的元素。

特殊的:如果把排序数组的前0个元素搬到最后面,即排序数组本身,这仍然是一个旋转。因此在上述的思路中,将中间节点元素的指针初始化为p1,即如果array[p1]>array[p2]不成立(数组有序),则直接返回数组中第一个元素即为最小的元素。

更特殊的:考虑如下两个旋转后的数组,第一个数字,最后一个数字和中间的数字都是1,无法使用上述的条件进行查找,此时就只能使用顺序查找的方法对数组中最小的元素进行查找了。

代码如下:

/**
 * 面试题11:旋转数组中最小的数字
 */
public class FindMinNumber {

    public static int findMinNumberInOrder(int[] array) {
        int min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
        }
        return min;
    }

    public static void findMinNumber(int[] array) {
        if (array.length <= 0)
            return;
        int p1 = 0;
        int p2 = array.length - 1;
        int mid = p1;
        while (array[p1] >= array[p2]) {
            if (p2 - p1 == 1) {
                System.out.println(array[p2]);
                break;
            }
            mid = (p1+p2) / 2;

            // 针对p1,p2和mid指向的元素相同时,只能使用顺序查找的方法
            if (array[p1] == array[p2] && array[p1] == array[mid]) {
                System.out.println(findMinNumberInOrder(array));
                break;
            }

            if (array[mid] >= array[p1]) {
                p1 = mid;
            } else if (array[mid] <= array[p2]) {
                p2 = mid;
            }
        }
    }

    public static void main(String[] args) {
        int[] array1 = {3,4,5,1,2};
        int[] array2 = {1,0,1,1,1};
        int[] array3 = {1,1,1,0,1};
        findMinNumber(array1);
        findMinNumber(array2);
        findMinNumber(array3);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值