LeetCode 154 Find Minimum in Rotated Sorted Array II

248 阅读2分钟

LeetCode 154 Find Minimum in Rotated Sorted Array II

思路

  1. 本题和LeetCode 81和LeetCode 153类似。当left、mid和right指向的元素大小相同时,是不能确定搜索区间应该如何变化的。所以,办法是保证left、mid和right不会同时指向大小相同的元素。当mid != left && nums[left] == nums[mid]的时候,++left即可。因为当区间大小为2时,倘若出现最小值是left所指向的值的情况,此时不能++left,如果++left会错过最小值。

倘若输入序列是[1,1,1,1,2,1,1],最后返回的结果是2后面的第一个1。本题的解法一是完备的。

  1. 本题也可以关注右边界,但是这个解法是不完备的。对于[1,1,1,1,2,1,1],返回的结果是第一个1。

  2. 将解法二修改为完备的。显然,对于输入序列[1,1,1,1,2,1,1]。在right减为5时,left为0,此时left,mid和right指向的元素相同,right会被减为4。这就是解法2不完备的原因,此时应该不减right,应该检查right和right-1所指向的元素间的大小关系。如果nums[right] >= nums[right-1],说明此时的right并没有指向递增子序列的开头,可以自减right。如果nums[right] < nums[right-1],说明right指向递增子序列的开头,直接返回right即可。因为整个序列中,满足nums[right] < nums[right-1]的,只有这一处。

Note: 本题不能使用LeetCode 81中曾经用过的

if (nums[left] == nums[mid] && nums[mid] == nums[right]) {
    --right;
    ++left;
    continue;
}

原因是,LeetCode 81是查找target是否存在,且在上述条件判断前,先检查了target是否等于nums[mid]。而本题是找到最小值,这一值是肯定存在的,上述条件会导致错过最小值,特别是当[left, right]的区间长度为2时。

代码

解法一

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

解法二

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

解法三

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