本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
整数数组
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。你必须设计一个时间复杂度为
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] <= 104nums中的每个值都 独一无二- 题目数据保证
nums在预先未知的某个下标上进行了旋转-104 <= target <= 104
思路:
-
题目规定要用时间复杂度为
O(log n)的算法解决此问题,且为无重复元素的排序数组,可采用二分查找的变种法 -
判断mid左侧是单调递增区间还是右侧为单调递增区间
-
若mid左侧是单调递增区间:
- 判断target是否在左侧单调递增区间内,若在则缩小右边界 right = mid - 1,若不在则在mid右侧 left = mid + 1(查找范围都是以mid为中心,分别向数组两头不断缩小查找范围)
-
若mid右侧为单调递增区间:
- 判断target是否在右侧单调递增区间内,若在则缩小左边界 left = mid + 1,若不在则在mid左侧 right = mid - 1(查找范围都是以mid为中心,分别向数组两头不断缩小查找范围)
-
时间复杂度: O(logN)
空间复杂度: O(1)
// 二分查找,时间复杂度:O(logN)
func search(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right - left) / 2
// mid := (left + right) / 2
if nums[mid] == target {
return mid
} else if nums[left] <= nums[mid] { // mid的左侧是单调递增区间
// 注意避免错误写法,上面已对mid判断过了:target <= nums[mid]
if nums[left] <= target && target < nums[mid] {
right = mid - 1
} else {
left = mid + 1
}
} else { // mid的右侧是单调递增区间
if nums[mid] < target && target <= nums[right] {
left = mid + 1
} else {
right = mid - 1
}
}
}
return -1
}