LeetCode-33-搜索旋转排序数组


题意描述:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

你可以假设数组中不存在重复的元素。

你的算法时间复杂度必须是 O(log n) 级别。


示例:

示例一:

输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例二:

输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

解题思路:

Alice: 给你一个 升序排序的数组,如何在 O(n * log n) 的时间复杂度内 查找一个元素呢 ?
Bob: 二分查找啊 ?
Alice: 那这道题怎么做呢 ?
Bob: 这个旋转排序数组不就是两个排序数组拼起来的吗,你把它在分成两个排序数组用两次二分查找不就好了吗。
Alice: 好像是的,不错不错。不过时间复杂度呢,怎么找到旋转的点,把两个排序数组分开呢 ?
Bob: 直接遍历呗,(ΩДΩ) 这样子时间复杂度应该就是O(n log n) + O (n) 了,不过应该也能过。
Alice: 肯定有直接 O(n log n)的写法,╭(╯^╰)╮
Bob: 那就应该是在 找旋转点的时候也用二分查找。。。😵


代码:
Python 方法一:二分查找

class Solution:
    def search(self, nums: List[int], target: int) -> int:

        if len(nums) == 0:
            return -1
        elif len(nums) == 1:
            if nums[0] == target:
                return 0
            else:
                return -1
        elif len(nums) == 2:
            if nums[0] == target:
                return 0
            elif nums[1] == target:
                return 1
            else:
                return -1
        
        # 查找旋转的点
        bound = 0
        for x in range(1, len(nums)):
            if nums[x] < nums[x-1]:
                bound = x
                break
                
        # 根据旋转点,对数组进行两次二分查找
        res1 = self.binarySearchAse(nums, 0, bound-1, target)
        res2 = self.binarySearchAse(nums, bound, len(nums)-1, target)

        if res1 == -1 and res2 == -1:
            return -1
        elif res1 == -1 and res2 != -1:
            return res2
        elif res1 != -1 and res2 == -1:
            return res1
    
    def  binarySearchAse(self, nums: List[int], left: int, right: int, target: int) -> int:
        # 升序数组的二分查找
        while left <= right:
            middle = (left + right) // 2
            if nums[middle] == target:
                return middle
            elif nums[middle] < target:
                left = middle + 1
            else:
                right = middle - 1
        return -1

Java 方法一: 二分查找

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length < 3){
           // 对于边界输入,直接查找。当数组长度为2的时候,旋转后的数组可能直接变为递减的。
            for(int i=0; i<nums.length; ++i){
                if(nums[i] == target){
                    return i;
                }
            }
            return -1;
        }else{
            int boundary = 0;
            for(int i=1; i<nums.length; ++i){
                // 查找旋转点
                if(nums[i] < nums[i-1]){
                    boundary = i;
                    break;
                }
            }

            int res1 = binarySearchAse(nums, 0, boundary-1, target);
            int res2 = binarySearchAse(nums, boundary, nums.length-1, target);
            int res  = -1;
            // 处理两次二分查找的结果

            if(res1 == -1 && res2 != -1){
                res = res2;
            }else if(res1 != -1 && res2 == -1){
                res = res1;
            }

            return res;
        }
    }
    public int binarySearchAse(int[] nums, int left, int right, int target){

        while(left <= right){
            int middle = (left + right) / 2;
            if(nums[middle] == target){
                return middle;
            }else if(nums[middle] < target){
                left = middle + 1;
            }else{
                right = middle - 1;
            }
        }
        return -1;
    }
}

易错点:

  • 一些边界值输入容易出错。
[3,1,2]
3
[3,5,1]
1
[4,5,6,7,0,1,2]
0
[4,5,6,7,0,1,2]
3
[1]
1
[1]
0
[1,2]
2
[1,2]
1
[3,1,2]
2
  • 答案:
0
2
4
-1
0
-1
1
0
2

总结:
在这里插入图片描述
在这里插入图片描述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值