旋转数组的最小数字-Java实现

12. 旋转数组的最小数字

问题描述

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

很容易我们想到的是,从头到尾遍历一次数据,我们就找出了最小值,时间复杂度是O(n),但是我们一点都没有用到旋转数组的特性.

分析

  1. 旋转数组,其实可以划分为两个排序的子数组,而且前面的子数组的元素都大于后面子数组的元素
  2. 最小值刚好就是这两个子数组的分界线
  3. 我们可以尝试用二分查找来实现(时间复杂度 O(logn))

代码如下:

/**
 * Class day12 ...
 *
 * @author LiJun
 * Created on 2018/12/28
 */
public class day12 {
    public static int Min(int[] numbers) {
        // 参数有效性验证
        if (numbers == null || numbers.length <= 0) {
            return Integer.MIN_VALUE;
        }
        // 二分法的基本实现就是一个指向头 一个指向尾
        int start = 0;
        int end = numbers.length - 1;
        // 设置medium的原因是一旦数组中的第一个数字 小于最后一个数字,说明这个数组是排序的
        // 直接返回第一个数字就行
        int medium = start;
        while (numbers[start] >= numbers[end]) {
            // 如果start 和 end 执行相邻的数字
            // 则 start 执行第一个递增数列的最后一个数字
            // end 指向第二个递增数列的第一个数字
            if (end - start == 1) {
                medium = end;
                break;
            }
            medium = (start + end) / 2;
            // 这里是特殊情况 如果这三者相等的话,就只能老老实实的顺序查找了
            if(numbers[start] == numbers[medium] && numbers[medium]  == numbers[end]){
                return GetMinInOrder(numbers, start, end);
            }
            if(numbers[medium] >= numbers[end]){
                start = medium;
            }else if(numbers[medium] <= numbers[end]){
                end = medium;
            }
        }
        return numbers[medium];
    }

    public static int GetMinInOrder(int[] numbers, int start, int end) {
        int min = numbers[start];
        for(int i = start+1; i <= end; i++){
            if(numbers[i] < min){
                min = numbers[i];
            }
        }
        return min;
    }

    public static void main(String[] args) {
        // 基础测试
        int[] numbers = {3,4,5,1,2};
        System.out.println(Min(numbers));
        numbers = new int[]{1, 0, 1, 1, 1};
        System.out.println(Min(numbers));
    }
}

在这我需要解释下,如果numbers[start] < numbers[end] 这就说明,这区间已经是排序好了的,无须查找了。

其次,有种情况,那就是 根据旋转数组的特性,第一个数字总是大于或者等于最后一个数字,那么我们现在想想,如果我们把 0 个数据搬到后面去 这时候第一个数据就是最小的,这也就是我们为什么把 medium 初始为 start 的值的原因。

但是我们也有种情没考虑到,当 numbers[start] = numbers[end] =numbers[medium] 的时候, 这个时候,我们应该怎么办呢。 例如: {1, 0, 1, 1, 1} 之类的,我们可以得到 numbers[medium] = 1 这三个值都相等的时候,我们怎样二分。我们只能老老实实的顺序遍历找出答案了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值