LeetCode--旋转有序数组大总结

        我们知道在一段有序的数组里面查找某一个数字时可以使用二分查找算法来实现o(lgn)时间复杂度的查找,现在题目给我们的数组是有序数组的旋转。比如原数组为(1,2,3,4,5,6,7),旋转后可能变成(2,3,4,5,6,7,1)或者(4,5,6,7,1,2,3)等等。可以发现旋转后的数组不在满足有序的特性了,因此不能直接的套用二分查找算法,但是观察可以发现,旋转之后的数组是分段有序的,比如:(4,5,6,7,1,2,3)数组中前半段(4,5,6,7)与后半段(1,2,3)都是递增序列,可以分别在两段数组上进行二分查找操作。因此在每次循环中需要判断哪一段是递增的。

LeetCode-33. Search in Rotated Sorted Array

输入:旋转数组,目标值

输出:返回目标值在旋转数组中的下标,如果不存在就返回 -1。

注意:旋转数组中的数值都不相同。

AC代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.empty())
            return -1;
        int lo = 0;
        int hi = (int)nums.size() - 1;
        while(lo <= hi)
        {
            int mid = lo + (hi - lo) / 2;
            if(nums[mid] == target)
                return mid;
            if(nums[lo] <= nums[mid]) //前一段递增
            {
                if(target < nums[mid] && target >= nums[lo])
                    hi = mid - 1;
                else
                    lo = mid + 1;
            }
            else //后一段递增
            {
                if(target > nums[mid] && target <= nums[hi])
                    lo = mid + 1;
                else
                    hi = mid - 1;
            }
        }
        
        return -1;
    }
};

LeetCode--81. Search in Rotated Sorted Array II

接着上一题:

输入:旋转数组,目标值。

输出:如果目标值出现在旋转数组中,输出true,否则输出false。

注意:本题与上一题的区别主要是旋转数组中可以有重复的数字。

在上一题中我们根据nums[lo]、nums[mid]、nums[hi]之间的关系来判断递增段,但是如果旋转数组中存在重复的数字的话,还需要多判断一种情况。比如考虑旋转数组:{1,1,0,1,1,1,1},第一次循环时,lo = 0,hi = 6,mid = 3。此时nums[lo] = nums[mid] = nums[hi] = 1,这样我们就没有办法判断出lo --- mid与mid --- hi 段哪一段是递增的了,这时可以只能采用线性遍历lo-hi段得出结论了。

AC代码如下:

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        if(nums.empty()) {
            return false;
        }
        int lo = 0;
        int hi = nums.size() - 1;
        while(lo <= hi) {
            int mid = lo + (hi - lo) / 2;
            if(nums[mid] == nums[lo] && nums[mid] == nums[hi]) {
                return count(nums.begin() + lo, nums.begin() + hi + 1, target) != 0;//STL函数
            }
            else if(nums[mid] == target) {
                return true;
            } else if(nums[lo] <= nums[mid]) { //前一段递增
                if(target < nums[mid] && target >= nums[lo]) {
                    hi = mid - 1;
                } else {
                    lo = mid + 1;
                }
            } else { //后一段递增
                if(target <= nums[hi] && target > nums[mid]) {
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
        }
        return false;
    }
};

LeetCode--153. Find Minimum in Rotated Sorted Array

输入:旋转数组;

输出:旋转数组的最小值;

注意:旋转数组中没有最小值。

这题与第一题类似,如果前一段是递增序列,那么最小值在后面;如果后一段是递增序列,那么最小值在前面。

AC代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        int lo = 0;
        int hi = (int)nums.size() - 1;
        while(lo < hi) {
            int mid = lo + (hi - lo) / 2;
            if(nums[mid] > nums[lo] && nums[mid] > nums[hi]) { //前一段是递增序列
                lo = mid + 1;
            } else if(nums[mid] < nums[hi] && nums[mid] < nums[lo]){ 
                //后一段是递增序列,注意到,这个地方 hi 不能等于 mid - 1,因为mid可能指向的就是最小值的索引。
                hi = mid;
            } else {  //执行到这里说明旋转数组是递增或者递减的,比如:没有旋转或者旋转的长度为数组的长度减1,那么返回首尾两端的最小值即可。
                return min(nums[lo], nums[hi]);
            }
        }
        return nums[lo];
    }
};

LeetCode--154. Find Minimum in Rotated Sorted Array II

接着上一题,输入输出都是一样的,不同的是本题中旋转数组中可以有重复的元素。那么与第二题类似,需要考虑一种特殊情况,就是无法判断哪一段是递增的时候,这时采用线性比较,找出最小值。

AC代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        int lo = 0;
        int hi = (int)nums.size() - 1;
        while(lo < hi) {
            int mid = lo + (hi - lo) / 2;
            if(nums[mid] == nums[lo] && nums[mid] == nums[hi]) { //无法判断哪一段递增,递减
                return *min_element(nums.begin() + lo, nums.begin() + hi + 1);//STL函数
            } else if(nums[mid] >= nums[lo] && nums[mid] > nums[hi]) { //前一段递增
                lo = mid + 1;
            } else if(nums[mid] <= nums[hi] && nums[mid] < nums[lo]) { //后一段递增
                hi = mid ;
            } else { //执行到这里说明旋转数组是递增或者递减的,比如:没有旋转或者旋转的长度为数组的长度减1,那么返回首尾两端的最小值即可。
                return min(nums[lo],nums[hi]);
            }
        }
        return nums[lo];
    }
};

如果大家有好的思路、疑问或者改进的方法,请留意告知,谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值