LeetCode每日一题 DAY5:LeetCode 33. 搜索旋转排序数组

33. 搜索旋转排序数组

 算法1
(三次二分检索)
O(logn)

1.数组长度为 0 和 1 时的特判处理。
2.首先二分出是以哪个元素分割数组两部分的。
3.具体为:每次二分时,如果 nums[mid] >= nums[l] && nums[mid] >= nums[r],则 l = mid + 1;如果 nums[mid] <= nums[l] && nums[mid] <= nums[r],则 r = mid;否则 break。最终数组分为 [0, l - 1] 和 [l, n - 1]两段区间。
4.然后再在两段区间分别二分找 target 即可。

时间复杂度
三次二分检索,时间复杂度是 O(logn)。

空间复杂度
仅需要常数的额外空间。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        if (n == 0)
            return -1;
        if (n == 1)
            return nums[0] == target ? 0 : -1;

        int l = 0, r = n - 1, pivot;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (nums[mid] >= nums[l] && nums[mid] >= nums[r])
                l = mid + 1;
            else if (nums[mid] <= nums[l] && nums[mid] <= nums[r])
                r = mid;
            else break;
        }
        pivot = l - 1;
        l = 0; r = pivot;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (nums[mid] < target)
                l = mid + 1;
            else
                r = mid;
        }
        if (nums[l] == target)
            return l;

        l = pivot + 1; r = n - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (nums[mid] < target)
                l = mid + 1;
            else
                r = mid;
        }
        if (nums[l] == target)
            return l;
        return -1;
    }
};

算法2
(一次二分检索)
O(logn) 

1.数组长度为 0 则直接返回 -1。
2.每一次二分,我们具体看一下什么时候答案可能在 [l, mid] 中,什么时候答案可能在 [mid + 1, r]中。
3.注意到 num[0] 是个非常关键的元素,已知数组被分为两个升序部分,且后半部分全部比nums[0] 小,如果 nums[i] >= nums[0],则说明 [0, i] 一定是升序的,否则 [i, n - 1] 一定是升序的。还可以根据 target 与 nums[0] 的关系,判断出 target 可能属于哪一部分。
4.根据 3,如果给定了一个位置 mid,我们可以根据 nums[0]、nums[mid] 与 target三者的关系,确定出 target 可能属于哪一段区间。具体看代码注释部分。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        if (n == 0)
            return -1;

        int l = 0, r = n - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (nums[mid] >= nums[0]) { // mid 在数组前半部分。
                if (target > nums[mid])
                    // 可以推出 target 的值一定大于 nums[0],target 只可能在 [mid + 1, r] 中。
                    l = mid + 1;
                if (target < nums[0])
                    // 可以推出 target 的值一定小于 nums[mid],target只可能在 [mid + 1, r] 中。
                    l = mid + 1;
                if (target <= nums[mid] && target >= nums[0])
                    // 此时 target 的值处于 nums[0] 和 nums[mid] 中,故可能在 [l, mid] 中。
                    r = mid;
            } else { // mid在数组后半部分
                if (target >= nums[0])
                    // 可以推出 target 的值一定大于 nums[mid],target只可能在 [l, mid] 中。
                    r = mid;    
                if (target <= nums[mid])
                    // 可以推出 target 的值一定小于 nums[0],target只可能在 [l, mid] 中。
                    r = mid;
                if (target > nums[mid] && target < nums[0])
                    // 此时 target 的值处于 nums[0] 和 nums[mid] 中,故可能在 [mid + 1, r] 中。
                    l = mid + 1;
            }
        }
        return nums[l] == target ? l : -1;
    }
};

 次解法主要记录学习过程,觉得大佬的学习方法比较容易理解,转载了wzc1995的题解,如若不适,可练习删帖。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值