【 剑指offer第2版-第12题-JAVA】

文章介绍了如何在已知递增排序的旋转数组中寻找最小元素,提出使用二分查找算法,通过比较中间元素与两端元素的关系来缩小搜索范围。在某些特殊情况下,如数组元素相等,需要进行顺序查找。文章提供了Java代码实现并附带测试用例。
摘要由CSDN通过智能技术生成

旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出该旋转数组的最小元素。
例如:数组{3,4,5,1,2}{1,2,3,4,5}的一个旋转,该数组的最小值为1.

本题最直观的解法就是从头遍历数组,已知是递增排序的数组,那么旋转后的数组,当第一次遇到数组中某一位小于它的前一位时,它即是最小值,此时的时间复杂度为O(n).此处我们不做代码实现,感兴趣的小伙伴可以自行尝试。
实际上,旋转后的数组可以划分为两个递增排序的子数组,而且前面子数组的元素都大于或者等于后面子数组的元素。并且最小值刚好是这两个子数组的的分界线。所以可以使用二分查找来实现时间复杂度O(logn)。
二分法,先找到中间元素middle,如果middle位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素,且最小值位于后一递增子数组,这样我们可以把第一个指针指向middle;同理,如果middle位于后面的递增子数组,那么它应该小于或者等于middle;那我们可以将第二个指针指向middle。不论是移动第一个指针或者是第二个指针,这样我们都可以缩小查找范围,同时我们也需要考虑数组是否包含相同数字,以及两个指针和middle同时指向同一个元素的临界情况;此时,只能通过顺序对比查找了。
上代码。

 public static Integer findMin(int[] nums) {
        //常规判空
        if (nums == null || nums.length == 0) {
            return null;
        }
        int start = 0;
        int end = nums.length - 1;
        int middle = 0;
        while (nums[start] >= nums[end]) {
            //刚好相差1,即end为最小值
            if (end - start == 1) {
                middle = end;
                break;
            }
            middle = (start + end) >> 1;
            //如果start,end ,middle 三个值均相等,则无法通过移动指针,只能顺序查找
            if (nums[middle] == nums[start] && nums[middle] == nums[end]) {
                for (int i = start + 1; i <= end; ++i) {
                    if (nums[start] > nums[i]) {
                        return nums[i];
                    }
                }
            }
            //如果start<=middle,则说明最小值在后一递增子数组
            if (nums[middle] >= nums[start]) {
                start = middle;
            }
            //如果end<=middle,则说明最小值在前一递增子数组
            if (nums[middle] <= nums[end]) {
                end = middle;
            }
        }
        return nums[middle];
    }
    //测试用例
    public static void main(String[] args) {
        int nums[] = new int[]{3, 4, 5, 1, 2};
        System.out.println(FindMin.findMin(nums));

        int nums1[] = new int[]{1, 0, 1, 1, 1};
        System.out.println(FindMin.findMin(nums1));

        int nums2[] = new int[]{1, 1, 1, 0, 1};
        System.out.println(FindMin.findMin(nums1));
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值