Leetcode 33. 搜索旋转排序数组

160 阅读1分钟

Leetcode 33. 搜索旋转排序数组

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

❤️‍欢迎订阅java厂长《LeetCode每日一题》 ❤️‍

1、题目📑

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2]

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1

实例1

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

输出:4

实例2

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

输出:-1

实例3

输入:nums = [1], target = 0

输出:-1

提示

  • 1 <= nums.length <= 5000
  • -10^4 <= nums[i] <= 10^4
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -10^4 <= target <= 10^4

进阶:你可以设计一个时间复杂度为 O(log n) 的解决方案吗?

2、思路🧠

方法一:二分查找

本题的难点在于在看到题目下面的进阶版本的时候就应该要想到使用二分法进行求解,但是具体的过程,还是需要进一步分析之后才能进行求解。

先复习一下二分查找:

public int search(int[] nums, int target) {
    int l = 0, r = nums.length - 1, mid = 0;
    while (l <= r) {
        mid = l + ((r - l) >> 1);
        if (nums[mid] == target) {
            return mid;
        }
        if (nums[mid] < target) {
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return -1;
}
  1. 明白旋转数组后,从某一个位置划分后,两段数组都是有序的数组。
  2. 这里就特殊在使用了中点进行分割两个数组来进行二分查找,通过分析可以得到数组的一侧是有序的,另一侧一定是无序的。
  3. 分析得到在中点的一侧一定是有序的,所以根据有序的特性用两个边界值来判断目标值在有序一侧还是无序一侧
  4. 分析题目需要找目标值,遇到目标值即返回当前目标值的位置

注意:由于有序的一边的边界值可能等于目标值,所以在判断目标值是否在有序一侧时应该加上等号,换句话说也就是在二分查找某个具体值的时候如果边界值不好把握,可以在每次查找前判断边界值,也就是说while循环里面的两个if注释。

while(left <= right){
    // if(nums[left] == target) return left;
    // if(nums[right] == target) return right;

    int mid = left + ((right - left) >> 1);
}

废话少说~~~~~上代码!

3、代码👨‍💻

第一次commit AC

class Solution {
    public int search(int[] nums, int target) {
        int l = 0,r = nums.length - 1;
        while(l <= r) {
            int mid = l + ((r - l) >> 1);
            if(nums[mid] == target) {
                return mid;
            }else if(nums[mid] > nums[r]) {
                //说明在左半段有有序的
                if(target >= nums[l] && target < nums[mid]) 
                    r = mid - 1;
                else 
                    l = mid + 1;
            }else {//nums[mid] < nums[r]
                if(target <= nums[r] && target > nums[mid])
                    l = mid + 1;
                else
                    r = mid - 1;
            }
        }
        return -1;
    }
}

时间复杂度:O(log N)

空间复杂度:O(1)

image-20220605192648397

4、总结

该题目的对二分法的过程以及思想通过对题目的灵活变换的考察,如果能够理解二分过程十分透彻的话,拿下此题应该不是问题。

❤️‍来自专栏《LeetCode基础算法题》欢迎订阅❤️‍

厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。

对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!

原题链接:33. 搜索旋转排序数组 - 力扣(LeetCode)