【二分查找】【打卡102天】《剑指Offer》2刷:JZ11 旋转数组的最小数字

1、题目描述

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000

要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)

2、算法分析

 mid = left + (right - left) /2,共有3种情况:

比较的话,中间值mid

(1)array[mid] > array[right]

出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边

low = mid + 1

(2)array[mid] == array[right]:

出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边

还是右边,这时只好一个一个试 ,

high--;

(3)array[mid] < array[right]:

出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左

边。因为右边必然都是递增的。

right = mid

注意这里有个坑:如果待查询的范围最后只剩两个数,那么mid 一定会指向下标靠前的数字

比如 array = [4,6]

array[low] = 4 ;array[mid] = 4 ; array[high] = 6 ;

如果high = mid - 1,就会产生错误, 因此high = mid

但情形(1)中low = mid + 1就不会错误

3、代码实现

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array == null || array.length == 0){
            return 0;
        }
        return binary(array,0,array.length-1);
    }
    public int binary(int[] arr,int left,int right){
        while(left < right){
            int mid = left + (right - left) / 2;
            if(arr[mid] > arr[right]){
                left = mid + 1;
            }else if(arr[mid] < arr[right]){
                // 防止 [4 ,6]这种2个数的情况
                right = mid ;
            }else{
                // [1,1,0,1,1,1,1]
                right--;
            }
        }
        // 因为数组是升序的,所以最小的一定在最左边。
        return arr[left];
    }
}

Guess you like

Origin blog.csdn.net/Sunshineoe/article/details/121469281