搜索旋转排序数组

GitHub跳转原题关系图返回列表

每轮二分判断哪一半有序,再判断 target 是否落在该半区,缩小搜索范围。

OJ: leetcodecn

题目 ID: search-in-rotated-sorted-array

难度:普及+/提高

标签:二分查找数组

日期: 2026-07-29 11:52

题意

给定旋转一次的升序无重复数组,查找 target 的下标,不存在返回 -1。要求 O(logn)O(\log n)

思路

虽然数组整体无序,但二分后必有一半是有序的。判断方法:若 nums[l] <= nums[mid],左半有序;否则右半有序。

确定有序半区后,判断 target 是否落在该半区的值域内:

  • 左半有序且 nums[l] <= target < nums[mid]r = mid - 1,搜索左半。
  • 左半有序但 target 不在左半:l = mid + 1,搜索右半。
  • 右半有序且 nums[mid] < target <= nums[r]l = mid + 1,搜索右半。
  • 右半有序但 target 不在右半:r = mid - 1,搜索左半。

每轮排除一半,保证 O(logn)O(\log n)

代码

cpp
#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    int search(vector<int> &nums, int target) {
        int l = 0, r = nums.size() - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (nums[mid] == target)
                return mid;
            if (nums[l] <= nums[mid]) {
                if (nums[l] <= target && target < nums[mid])
                    r = mid - 1;
                else
                    l = mid + 1;
            } else {
                if (nums[mid] < target && target <= nums[r])
                    l = mid + 1;
                else
                    r = mid - 1;
            }
        }
        return -1;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, t;
    cin >> n >> t;
    vector<int> a(n);
    for (int &x : a)
        cin >> x;
    cout << Solution().search(a, t) << '\n';
    return 0;
}
python
#!/usr/bin/env python3
from typing import List


class Solution:
    def search(self, nums: List[int], target: int) -> int:
        l, r = 0, len(nums) - 1
        while l <= r:
            m = (l + r) // 2
            if nums[m] == target:
                return m
            if nums[l] <= nums[m]:
                if nums[l] <= target < nums[m]:
                    r = m - 1
                else:
                    l = m + 1
            else:
                if nums[m] < target <= nums[r]:
                    l = m + 1
                else:
                    r = m - 1
        return -1


def main():
    n, t = map(int, input().split())
    a = list(map(int, input().split()))
    print(Solution().search(a, t))


if __name__ == "__main__":
    main()

复杂度

  • 时间复杂度:O(logn)O(\log n)
  • 空间复杂度:O(1)O(1)

总结

旋转数组二分的核心观察:二分后必有一半有序。先判断哪半有序,再判断 target 是否在该半区,从而缩小范围。nums[l] <= nums[mid] 的等号处理了 l == mid 的情况。