33. 搜索旋转排序数组

目录

一、问题描述

二、解题思路

三、代码

四、复杂度分析


一、问题描述

整数数组 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

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

二、解题思路

我们需要通过修改标准二分查找的算法来解决旋转数组的问题。具体步骤如下:

  • 取数组的中点 mid,将数组分为左右两部分。因为数组是旋转的,所以至少一部分(左半部分或右半部分)是有序的。
  • 检查目标值 target 是否在有序部分。如果是,则可以在这部分继续进行二分查找;如果不在,则去另一部分查找。
  • 继续重复二分查找,直到找到目标值或确定目标值不存在。

详细步骤:

  • 初始化 leftright 指针分别指向数组的左右两端。
  • left <= right 的条件下进行循环:
    • 计算中点 midmid = left + (right - left) / 2
    • 如果 nums[mid] == target,直接返回 mid
    • 判断哪一半是有序的:
      • 如果 nums[left] <= nums[mid],说明左半部分是有序的。
        • 判断 target 是否在左半部分:如果 nums[left] <= target < nums[mid],则在左半部分查找,更新 right = mid - 1;否则去右半部分查找,更新 left = mid + 1
      • 如果 nums[mid] <= nums[right],说明右半部分是有序的。
        • 判断 target 是否在右半部分:如果 nums[mid] < target <= nums[right],则在右半部分查找,更新 left = mid + 1;否则去左半部分查找,更新 right = mid - 1
  • 如果退出循环时还没有找到目标值,返回 -1。

三、代码

java 复制代码
class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;

        while (left <= right) {
            int mid = left + (right - left) / 2;

            // 如果找到了目标值,返回下标
            if (nums[mid] == target) {
                return mid;
            }

            // 判断左半部分是否有序
            if (nums[left] <= nums[mid]) {
                // 如果目标值在左半部分,则继续在左半部分查找
                if (nums[left] <= target && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    // 否则在右半部分查找
                    left = mid + 1;
                }
            } else {
                // 如果右半部分有序
                if (nums[mid] < target && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }

        // 如果没有找到目标值,返回 -1
        return -1;
    }
}

四、复杂度分析

  • 时间复杂度:由于每次将搜索空间缩小一半,因此时间复杂度是 O(log⁡n)O(\log n)O(logn),符合题目要求。
  • 空间复杂度:我们使用的是常数级别的额外空间,空间复杂度为 O(1)O(1)O(1)。
相关推荐
带刺的坐椅9 分钟前
qwen3 惊喜发布,用 ollama + solon ai (java) 尝个鲜
java·spring·solon·solon-ai·qwen3
Vacant Seat37 分钟前
贪心算法-跳跃游戏II
算法·游戏·贪心算法
.生产的驴42 分钟前
SpringBoot 接口国际化i18n 多语言返回 中英文切换 全球化 语言切换
java·开发语言·spring boot·后端·前端框架
夜松云1 小时前
从对数变换到深度框架:逻辑回归与交叉熵的数学原理及PyTorch实战
pytorch·算法·逻辑回归·梯度下降·交叉熵·对数变换·sigmoid函数
Howard_Stark1 小时前
Spring的BeanFactory和FactoryBean的区别
java·后端·spring
饮长安千年月1 小时前
学生管理系统审计
java·网络安全·代码审计
八股文领域大手子1 小时前
深入浅出限流算法(三):追求极致精确的滑动日志
开发语言·数据结构·算法·leetcode·mybatis·哈希算法
-曾牛1 小时前
Spring Boot中@RequestParam、@RequestBody、@PathVariable的区别与使用
java·spring boot·后端·intellij-idea·注解·spring boot 注解·混淆用法
新时代苦力工1 小时前
处理对象集合,输出Map<String, Map<String, List<MyObject>>>格式数据,无序组合键处理方法
java·数据结构·list
啊阿狸不会拉杆1 小时前
人工智能数学基础(一):人工智能与数学
人工智能·python·算法