Gear with Code Java Engineer

剑指Offer-旋转数组的最小数字

2019-11-27

1 题目描述

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

2 思路分析

  1. 遍历一次肯定能找到结果,时间复杂度为O(n),这题给的数组是有序数组旋转得来的,在有序数组中查找一个数可以用二分查找,时间复杂度为O(logn)。对于这题是不是也可以想办法把时间复杂度降到O(logn)呢?

  2. 对于有序数组来说,它的最小值就是它的第一个元素,那么我们如果将旋转数组二分的话,很大概率上会得到一个有序数组和一个旋转数组,对于有序数组那一半我们可以直接得到最小值,对于旋转数组那一半就递归解决。这样每次减少一半的情况时间复杂度就是O(logn)。

    1574842087117

  3. 那么怎么判断哪一半是有序数组呢?如果是旋转过的数组,那么第一个元素一定大于等于最后一个元素,反之,如果第一个元素小于最后一个元素就是有序数组了。

3 示例代码

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        return minNumberInRotateArray1(array, 0, array.length - 1);
    }
    /*
    思路:
        遍历一次肯定能找到结果,时间复杂度为O(n),这题给的数组是有序数组旋转得来的,
    在有序数组中查找一个数可以用二分查找,时间复杂度为O(logn)。对于这题是不是也可以
    想办法把时间复杂度降到O(logn)呢?
        对于有序数组来说,它的最小值就是它的第一个元素,那么我们如果将旋转数组二分的话,
    很大概率上会得到一个有序数组和一个旋转数组,对于有序数组那一半我们可以直接得到最小值,
    对于旋转数组那一半就递归解决。这样每次减少一半的情况时间复杂度就是O(logn)。
        那么怎么判断哪一半是有序数组呢?如果是旋转过的数组,那么第一个元素一定大于等于
    最后一个元素,反之,如果第一个元素小于最后一个元素就是有序数组了。
    */
    public int minNumberInRotateArray1(int [] array, int f, int l) {
        // 如果数组只有一个元素,直接返回
        if (f == l) {
            return array[f];
        }
        
        // 如果第一个元素小于最后一个元素,直接返回第一个元素
        if (array[f] < array[l]) {
            return array[f];
        }
        
        // 将数组二分
        int mid = (f + l) / 2;
        // 递归处理
        int leftResult = minNumberInRotateArray1(array, f, mid);
        int rightResult = minNumberInRotateArray1(array, mid + 1, l);
        
        // 返回递归结果中较小的那一个
        return leftResult < rightResult ? leftResult : rightResult;
    }
}

Similar Posts

Comments