33. 搜索旋转排序数组
整数数组 nums
按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums
在预先未知的某个下标 k
(0 <= 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) 。我们只需要常数级别的空间存放变量。
//时间Ologn,空间O1
func search(nums []int, target int) int {
left, right := 0, len(nums) -1
for left <= right {
mid := left + (right - left) /2
if nums[mid] == target { // 判断正好相等,完事
return mid
} else if nums[mid] >= nums[left] { // 判断有序在左
if nums[mid] > target && target >= nums[left] { // 判断目标值在 有序区间 左边内
right = mid - 1
} else {
left = mid + 1
}
} else if nums[mid] < nums[left] { // 判断左边不是有序,即有序在右
if nums[mid] < target && target <= nums[right] { // 判断目标值在 有序区间 右边内
left = mid + 1
} else {
right = mid -1
}
}
}
return -1
}