LeetCode 33 搜索旋转排序数组

230 阅读2分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。

前言:emmm,题目看了好几分钟,一直在想题目要干啥。。。看了一眼评论,想着难道真的是我想的那样,于是写了一下简单的暴力解法,accept。。。当然,题目为中等,解法肯定不是我这个。

题目:给定一个数组(数组中元素唯一)和一个target, 如果target在数组中,返回其下标,如果不在返回-1。此外还介绍了旋转数组,指的就是数组在某个下标i处进行旋转,旋转后数组就变成arr[i, len, 0, i]。举例:[1, 2, 4]i=1处旋转,则数组变成[2,4,1]

暴力解法

暴力解法很简单,就是遍历数组,查看数组每个元素是否等于target,如果等于就返回下标,不等就直到循环结束返回-1,代码如下:

public int search(int[] nums, int target) {
        int len=nums.length;
        for(int i=0;i<len;i++){
            if(nums[i] == target){
                return i;
            }
        }
        return -1;
    }

最终运行结果耗时0ms,超过100%人。。。。

当然编题目的人肯定是不希望答案是这个,毕竟前面花费那么多文字解释什么是旋转数组,并且进阶版要求时间复杂度为O(logN)O(logN),上述解法的时间复杂度为O(N)O(N)

二分法

看到时间复杂度为O(logN)O(logN),首先想到的就是二分法,本题给的数组是原数组保持有序后经过翻转的数组,此时使用二分法将数组二分,则数组必然有一个保持有序,另一侧部分有序。**通过判断target在哪个数组来再次进行二分就是本题的关键点。**其实就是判断数组的哪部分有序。

可以通过判断首元素与mid元素的大小来确定[0-mid]是否有序,如果有序则直接判断target是否在这个范围,即nums[0]<target<nums[mid],是则更新r,否则更新l。如果无序则判断target是否在nums[mid]<target<nums[n-1],如果在则更新l,否则更新r。代码如下:

public int search2(int[] nums, int target) {
        int l=0, r=nums.length-1;
        while (l<=r){
            int mid = (l + r) /2;
            if(nums[mid] == target){
                return mid;
            }
            if(nums[0]<=nums[mid]){  //这一步用来判断数组哪部分有序,该条件为左边有序
                if(nums[0]<=target&&target<nums[mid]){
                    r = mid - 1;
                }else {
                    l = mid + 1;
                }
            }else { // 否则右边有序
                if(nums[mid]<target&&target<=nums[nums.length-1]){
                    l = mid + 1;
                }else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }

时间复杂度为O(logN)O(logN), 空间复杂度为O(1)O(1)