题目
整数数组
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.初始化指针:left
和 right
分别指向数组的首尾
2.循环查找:
1.计算中间位置 mid
2.如果 nums[mid]
正好是目标值,直接返回 mid
3.判断哪部分是有序的:
图片来源于视频截图https://www.bilibili.com/video/BV1tz421r7xC?vd_source=b42b3b4ccc197fbbaf3f1dbdb048417a
区间可分为左右两个区间,每个区间都是有序单调递增的。
1.如果 nums[left] <= nums[mid]
,说明左半部分是有序的
1.检查目标值是否在左半部分的范围内:nums[left] <= target < nums[mid]
2.如果是,则在左半部分继续搜索 (right = mid - 1
)
3.否则在右半部分搜索 (left = mid + 1
)
2.否则右半部分是有序的
1.检查目标值是否在右半部分的范围内:nums[mid] < target <= nums[right]
2.如果是,则在右半部分继续搜索 (left = mid + 1
)
3.否则在左半部分搜索 (right = mid - 1
)
4.未找到返回:如果循环结束仍未找到,返回 -1
var search = function (nums, target) {
let left = 0
let right = nums.length - 1
while (left <= right) {
let mid = Math.floor((left + right) / 2) // 计算中间位置
if (nums[mid] === target) return mid // 找到目标值直接返回
// 判断左半部分是否有序
if (nums[left] <= nums[mid]) {
// 如果目标值在有序的左半部分范围内
if (nums[left] <= target && target < nums[mid]) {
right = mid - 1 // 在左半部分继续搜索
} else {
left = mid + 1 // 否则在右半部分搜索
}
}
// 右半部分有序
else {
// 如果目标值在有序的右半部分范围内
if (nums[right] >= target && target > nums[mid]) {
left = mid + 1 // 在右半部分继续搜索
} else {
right = mid - 1 // 否则在左半部分搜索
}
}
}
return -1 // 未找到目标值
}