【LeetCode刷题】154. 寻找旋转排序数组中的最小值 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

=====================================================================================================================================================================================================

思路:
旋转排序数组 numsnums 可以被拆分为 2 个排序数组 nums1nums1 , nums2nums2 ,并且 nums1任一元素 >= nums2任一元素;因此,考虑二分法寻找此两数组的分界点 nums[i]nums[i] (即第 2 个数组的首个元素)。


设置 leftleft, rightright 指针在 numsnums 数组两端,midmid 为每次二分的中点:
(1)当 nums[mid] > nums[right]时,midmid 一定在第 1 个排序数组中,ii 一定满足 mid < i <= right,因此执行 left = mid + 1;
(2)当 nums[mid] < nums[right] 时,midmid 一定在第 2 个排序数组中,ii 一定满足 left < i <= mid,因此执行 right = mid;
(3)当 nums[mid] == nums[right] 时,是此题对比 153题 的难点(原因是此题中数组的元素可重复,难以判断分界点 ii 指针区间);


例如 [1, 0, 1, 1, 1][1,0,1,1,1] 和 [1, 1, 1, 0, 1][1,1,1,0,1] ,在 left = 0, right = 4, mid = 2 时,无法判断 midmid 在哪个排序数组中。
我们采用 right = right - 1 解决此问题,证明:
此操作不会使数组越界:因为迭代条件保证了 right > left >= 0;
此操作不会使最小值丢失:假设 nums[right]nums[right] 是最小值,有两种情况:
若 nums[right]nums[right] 是唯一最小值:那就不可能满足判断条件 nums[mid] == nums[right],因为 mid < right(left != right 且 mid = (left + right) // 2 向下取整);
若 nums[right]nums[right] 不是唯一最小值,由于 mid < right 而 nums[mid] == nums[right],即还有最小值存在于 [left, right - 1][left,right−1] 区间,因此不会丢失最小值。
以上是理论分析,可以代入以下数组辅助思考:
[1, 2, 3][1,2,3]
[1, 1, 0, 1][1,1,0,1]
[1, 0, 1, 1, 1][1,0,1,1,1]
[1, 1, 1, 1][1,1,1,1]
时间复杂度 O(logN)O(logN),在特例情况下会退化到 O(N)O(N)(例如 [1, 1, 1, 1][1,1,1,1])。


转自:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/solution/154-find-minimum-in-rotated-sorted-array-ii-by-jyd/

class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0;
        int right = nums.size()-1;
        while(left < right)
        {
            int mid = (left + right) /2;
            if(nums[mid] > nums[right])
            {
                left = mid + 1;
            }
            else if(nums[mid] < nums[right])
            {
                right = mid;
            }
            else
            {
                right  = right -1;
            }
        }
        return nums[left];
    }
};

https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值