【Java】牛客_剑指offer(JZ6) 旋转数组的最小数字

题目来源:https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&&tqId=11159&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目描述

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

题解

解题思路:

  • 首先,这肯定是一个查找问题,可以直接暴力排序然后找出最小值,但是肯定不太符合出题意愿。
  • 因为,旋转数组的原数组是非递减排序的,即原数组是升序的,数字可以重复。
  • 所以,将数组的开始部分搬到数组的末尾后,可以发现:数组左部分 > 数组右部分,即最小值在右部分第一个数
  • 因为数组可以看作有序,所以可以用二分查找,但是没有目标值target,即没有确定最小值,这就是这道题的难点,所以这里不是target与中间值比较,而是中间值与最右边值比较
    1. array[mid] < array[high],可以知道中间值array[mid]在右部分,但是mid不一定是最小,所以high左移,high = mid注意这里high不是mid-1是避免mid刚好是最小值
    2. array[mid] > array[high],可以知道中间值array[mid]在左部分,所以low右移,low = mid + 1
    3. array[mid] = array[high]遇到重复数字,high左移一位
    4. 最后,当low = high时,就是最小值

代码实现

/**
 * 二分查找
 */
public class Solution {
    public int minNumberInRotateArray(int[] array) {
        // 判空处理
        if (array == null || array.length == 0) {
            return 0;
        }
        int low = 0;
        int high = array.length - 1;
        // 这里是为了找到最小值,low = high时为最小值,所以可以不用比较 low = high
        while (low < high) {
            // 这里的 mid 没有使用 mid=(low+high)/2,是避免oj中的加法发生溢出
            int mid = low + (high - low) / 2;
            // 如果 array[mid] < array[high],array[mid]是右部分元素,所以high左移
            if (array[mid] < array[high]) {
                // 这里与原来二分查找的区别,不是high=mid-1,是为了避免 mid 刚好是最小值
                high = mid;
            }
            // 如果 array[mid] > array[high],array[mid]是左部分元素,所以low右移
            else if (array[mid] > array[high]) {
                low = mid + 1;
            }
            // 如果 array[mid] = array[high] 遇到重复数字,high左移一位
            else {
                high -= 1;
            }
        }
        return array[low];
    }
}

你可能感兴趣的:(nowcoder)