0
点赞
收藏
分享

微信扫一扫

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

云朵里的佛光 2022-03-12 阅读 34

原题链接:力扣icon-default.png?t=M276https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/

该题是153题的延伸,不同之处在于有了“重复元素”

对于原数组An处于升序序列,意味着A[0]肯定是最小值,An肯定是左边小右边大!

因此我们可以利用这个性质进行一个low high 指针的调动

对于传统二分模板,我们有取中间值公式Mid=Low+(High-Low)/2

因此我们对旋转过的数组进行取中值的时候,有以下情况

1.nums[Mid]>nums[High]

这是什么意思?意思是中间的值比最左端(不一定是nums.size这个端)要大,这并不符合我们原有序数组的左小右大的规律,这恰好说明了Mid指针跨越了两个分部的数组,这又是什么意思?

 这说明Mid指针至少从最大值饶了一个弯!因为他本来是大的部分,却往后走回到小的部分,说明中间已经经过了nums[nums.size()-1]了!那中间必定经过最小值,因为我们知道原数组的第一个元素就是最小值,那么很显然,答案就在Mid跟High之间

2.nums[Mid]<nums[High]

这说明此时Mid到High部分的元素有序,那说明原来数组的右边(偏大一方)的部分元素被扔到了Mid左边去了或者翻转后的数组本身就是有序的!既然如此,我们不妨测试一下Low到Mid之间的数,借助情况①的判断来确定边界,为什么不能直接移动呢,因为我们并不知道此时哪边是大的值!例如012345,此时3<5,但答案在0~2测,所以我们不妨测试0~2范围内是否存在答案,如果一直符合情况②,那么High指针就会一直回缩,一直到缩到一号位

那如果确实是下图这种情况呢?我们仍然不妨试试将high指针放回mid处,此时注意,mid处是小值,但mid左侧是比较大的值!这样会导致low指针马上调到新的mid之间,low会往后移,mid也会往后移,直到low指针处于数值1的位置,此时注意前两行刚说过,high指针已经放回了最开始的mid处,我们已经知道在这区间1是最小的了,那low指针不断缩进,直到两指针相撞找到答案

其实用逻辑思考也想得通,一个有序的数组,他成环形,他既是左边一部分的最小值,也是右边一部分的最小值,那他肯定是这个环形数组的最小值

 

(注意上图两个指针均为mid指针和high指针)

3.nums[Mid]==nums[High]

举例入 451333 此时mid指针在3号位数值为3,high指针在5号位数值为3,其实这种情况跟小于的情况差不多,其实都能说明这段区间是有序的,但我们无法确定这到底是大的区间,还是小的区间,例如 012333,显然最小值在low mid之间,那么此时就可以任意移动一个指针,使得重新计算出来的mid不在这个3上就可以了,因为无法确定,即使两个元素其中之一被忽略了并不影响我们的判断!例如此时我们把末尾3忽略,此时就为 01233,计算出来的值为 mid=5/2+0=2,就得到了2 3的对比,以此类推到情况②一直到情况①,最后回推到答案,因为3并不具有边界确定关系,即使答案就是3,忽略了一方,另一方总是能成为找到答案的替代品!

最终代码成品:


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

 

如果文章有错误地方,还希望您不惜赐教

希望笔者的文章能带给您收获!

举报

相关推荐

0 条评论