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 。 字节考过。

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

  • 对于有序数组,可以使用二分查找的方法查找元素。
  • 但是这道题中,数组本身不是有序的,进行旋转后只保证了数组的局部是有序的,这还能进行二分查找吗?答案是可以的。
  • 其实题目要求还是求某个值在数组中的坐标,但是遍历的方法时间复杂度高,需要利用旋转过的升序数组这个条件来优化时间复杂度。
  • 二分的细节是核心。


  • 时间复杂度: O(logn),其中 n 为 nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度 O(logn)。
  • 空间复杂度: O(1) 。我们只需要常数级别的空间存放变量。

    1. //时间Ologn,空间O1
    2. func search(nums []int, target int) int {
    3. left, right := 0, len(nums) -1
    4. for left <= right {
    5. mid := left + (right - left) /2
    6. if nums[mid] == target { // 判断正好相等,完事
    7. return mid
    8. } else if nums[mid] >= nums[left] { // 判断有序在左
    9. if nums[mid] > target && target >= nums[left] { // 判断目标值在 有序区间 左边内
    10. right = mid - 1
    11. } else {
    12. left = mid + 1
    13. }
    14. } else if nums[mid] < nums[left] { // 判断左边不是有序,即有序在右
    15. if nums[mid] < target && target <= nums[right] { // 判断目标值在 有序区间 右边内
    16. left = mid + 1
    17. } else {
    18. right = mid -1
    19. }
    20. }
    21. }
    22. return -1
    23. }

image.png