2021.4.9

154. 寻找旋转排序数组中的最小值II

https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]

给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

示例 1:

输入:nums = [1,3,5]
输出:1

示例 2:

输入:nums = [2,2,2,0,1]
输出:0

提示:

n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转  

进阶:

这道题是 寻找旋转排序数组中的最小值 的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?


学到的知识点:emmm还是二分查找
本来是想博客上还是写点有价值的东西,别什么力扣题都网上扔的,但是一看这题困难,还是给个面子吧(
我写的hape代码:(C#)

public class Solution {
    public int FindMin(int[] nums) {
        int left=0;
        int right=nums.Length-1;
        while(left<=right){
            int middle = (left+right)/2;
            if(nums[middle]<nums[(middle-1+nums.Length)%nums.Length]){
                return nums[middle];
            }
            else if(nums[left] < nums[(left - 1 + nums.Length) % nums.Length])
            {
                return nums[left];
            }
            else if (nums[right] < nums[(right - 1 + nums.Length) % nums.Length])
            {
                return nums[right];
            }
            //因为最小值可能有多个,所以左中右都判断一下(

            if(nums[middle] == nums[left] && nums[middle] == nums[right]){
                left++;
                //只加left而不减right是为了防止在left=right-1时直接退出循环
                continue;
            }
            if(middle==left || nums[middle]>=nums[left] && nums[right]<=nums[left]){//最小值在右边
                left=middle+1;
            }
            else{
                right=middle-1;
            }
        }
        //意☆义☆不☆明的nums[0]
        return nums[0];
    }
}

学来的优雅代码:(C#)

public class Solution {
    public int FindMin(int[] nums) {
        int left=0;
        int right=nums.Length-1;
        while(left<right){
            int middle = (left+right)/2;
            if(nums[middle]>nums[right]){
                //最小值在右边
                left=middle+1;
            }
            else if(nums[middle]<nums[right]){
                //最小值在左边,或middle处
                right=middle;
            }
            else{
                right--;
            }
        }
        return nums[left];
    }
}

实际上只要比较nums[middle]和nums[right]就可以判断最小值在哪边了,这和二分查找不同。