力扣33-搜索旋转排序数组

33. 搜索旋转排序数组 - 力扣(LeetCode)

整数数组 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) 的算法解决此问题。

示例 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
  • -104 <= nums[i] <= 104
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

由于是旋转数组,所以具备以下性质:

任意取 nums 中的某个数 x 与 nums[n - 1] 比大小:

  • 如果 x > nums[n - 1],说明:nums 有两个递增段,且第一个递增段的所有元素均大于第二个递增段的所有元素,且 x 在第一个递增段
  • 如果 x ≤ nums[n - 1],那么 x 在第二个递增段,或者 nums 本身是递增数组,只有一段

设 x = nums[mid] 是我们要二分的数,要判断 x 和 target 的位置关系,将 x 和 target 这两个数与 nums[n - 1] 比大小:

  • 如果 target > nums[n - 1] ≥ x,则 target 在第一段,x 在第二段,target 在 x 左侧
  • 如果 x > nums[n - 1] ≥ target,则 x 在第一段,target 在第二段,target 在 x 右侧
  • 否则,x 和 target 在同一段,直接比较 x 与 target 的大小即可知谁在左边、谁在右边

知道了谁在左、谁在右,就能进行二分了

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = -1, len(nums) - 1
        while left + 1 < right:
            mid = (left + right) // 2
            x = nums[mid]
            if target > nums[-1] >= x:
                # target 在第一段,x 在第二段
                right = mid
            elif x > nums[-1] >= target:
                # target 在第二段,x 在第一段
                left = mid
            elif x >= target:
                # x 和 target 在同一段且 x 在 target 右侧
                right = mid
            else:
                left = mid
        return right if nums[right] == target else -1

什么时候是 left < right,什么时候是 left <= right,什么时候是 left + 1 < right?

做二分,搞清楚三个问题:

1.维护的区间是什么?

2.mid要不要保留?

3.区间是不是真的缩小了?

如果这题是 left 初始为 0 ,while 循环的条件是 left < right,那么可能会出现死循环,例如 left = 3,right = 4,那么 mid = 3,然后如果走了第二个分支,那么 mid 会赋值 给 left,那区间就没有缩小,就死循环了

那能不能 left = mid + 1?可以,但是不能同时 right = mid - 1,即 elif nums[mid] >= target 分支中不能写成 right = mid - 1,但 if target > nums[-1] >= nums[mid] 分支中就可以写 right = mid - 1,因为 elif 分支相当于 nums[mid] == target or nums[mid] > target,即 nums[mid] 是有可能成为答案的,如果你 right = mid - 1,那就把答案排除在区间之外了

所以也可以:

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            x = nums[mid]
            if target > nums[-1] >= x:
                # target 在第一段,x 在第二段
                right = mid - 1
            elif x > nums[-1] >= target:
                # target 在第二段,x 在第一段
                left = mid + 1
            elif x >= target:
                # x 和 target 在同一段且 x 在 target 右侧
                right = mid
            else:
                left = mid + 1
        return right if nums[right] == target else -1

处理输入输出版:

cases.txt:

复制代码
[4,5,6,7,0,1,2]
0
[4,5,6,7,0,1,2]
3
[1]
0

Python

python 复制代码
from typing import List
import ast

def search(nums: List[int], target: int) -> int:
    left, right = -1, len(nums) - 1
    while left + 1 < right:
        mid = (left + right) // 2
        x = nums[mid]
        if target > nums[-1] >= x:
            # target 在第一段,x 在第二段
            right = mid
        elif x > nums[-1] >= target:
            # x 在第一段,target 在第二段
            left = mid
        elif x >= target:
            # x 与 target 在同一段且 x 在 target 右侧
            right = mid
        else:
            # x 与 target 在同一段且 x 在 target 左侧
            left = mid
    return right if nums[right] == target else -1

def read_cases(filename: str):
    cases = []
    with open(filename, "r") as f:
        lines = [
            line.strip() for line in f
        ]

    for i in range(0, len(lines), 2):
        nums = ast.literal_eval(
            lines[i]
        )
        target = ast.literal_eval(
            lines[i + 1]
        )
        cases.append(
            (nums, target)
        )
    return cases

def main():
    cases = read_cases("cases.txt")
    for nums, target in cases:
        res = search(nums, target)
        print(f"nums = {nums}")
        print(f"target = {target}")
        print(f"result = {res}")
        print()

if __name__ == "__main__":
    main()
相关推荐
高亦真23 分钟前
今天是学习嵌入式的第37天
linux·学习·算法
罗西的思考2 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 --- (2)--- 训练
人工智能·算法·机器学习
深圳市方中禾科技3 小时前
FZH1625 LCD 驱动芯片深度评测与实战指南
算法·led
我不会起名字3224 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
测试老哥5 小时前
接口测试的测试用例应该怎么写?
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·接口测试
huang5791476 小时前
哈希算法的抗碰撞机制与安全性增强策略4
算法
林浩杨_6 小时前
SIGIR 2026|南京大学:Video-GAR:“通过生成 Query 来验证视频语义理解”的生成增强范式
论文阅读·人工智能·算法
CC数分6 小时前
2026年HRBP岗位硬性要求和加分项
面试·职场和发展·数据分析
Elsa️7467 小时前
算法一周刷题总结
c++·算法
小小程序猴17 小时前
深圳乘路资讯AI培训怎么样?课程靠谱吗?——一套课程可信度评估模型与实证分析
人工智能·算法