159.寻找旋转排序数组中的最小值(高频++)

描述

假设一个旋转排序的数组其起始位置是未知的比如:(0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2),你需要找到其中最小的元素。

注意事项

你可以假设数组中不存在重复的元素。

样例

给出[4,5,6,7,0,1,2] 返回 0

思路

  1. 找到一个分界点,以这个点为分界点将数组分为两部分,第一部分值大于分割点,第二部分值小于分割点,最小值为第二段区间的第一个点,本题要以数组最后一个元素作为数组的分界点
  2. 不能取第一个元素做分割点,当数组是没有旋转情况下,比如数组为1、2、3时,取第一个点作为分割点时数组分为两段分别是1和 2、3,程序返回第二段区间的第一个点是的是2,而正确结果应该是1。但如果取的是最后一个点 3 做分割,第一部分没有值,第二部分值为 1、2、3,则第二部分最小值为1,为最小值
  3. 不断二分最后锁定在断点两端的两个点上;但要考虑特殊情况比如正常的01234567顺序,start 和 end 两个点都小于 target,所以应该先判断 start 位置的元素

代码

public class Solution {
    public int findMin(int[] nums) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        
        int start = 0;
        int end = nums.length - 1;
        int target = nums[nums.length - 1];
        // target 即为将循环数组分为两部分的数值分界点(一部分大于target,一部分小于target)
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            /* 根据if条件判断mid是在循环数组的前面还是后面
             * 二分法会使得start和end最终返回在分界点,但
             * 到底是前面点还是后面点不确定,需要用if来检验
             * 求最小值往前找总是没错的
             */
            if (nums[mid] <= target) {
                end = mid;
            }
            if (nums[mid] > target) {
                start = mid;
            }
        }
 
        // nums[start] < target 说明数组未旋转
        // nums[end] = target 说明数组值都是相同值
        if (nums[start] <= target) {
             return nums[start];
        }
        else {
            return nums[end];
        }
    }
}

最后这个 double check 在特殊情况即 12345 这种未旋转顺序下可能出现 start <= target 如果不考虑这种特殊情况,double check 可以直接写成 return nums[end]

你可能感兴趣的:(159.寻找旋转排序数组中的最小值(高频++))