一、任务描述:
整数数组 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.length <= 5000
- -104 <= nums[i] <= 104
- nums 中的每个值都 独一无二
- 题目数据保证 nums 在预先未知的某个下标上进行了旋转
- -104 <= target <= 104
本题取自 leetcode 算法基础中级
> 示例 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
二、题意解析
根据示例,可以思考得出,数组nums存在一点,旋转了数组的数值结构(即上图分界点Point,存在 nums[Point] > nums[Point + 1]
)
所以我们可以总结以下规律:
- 若
nums[mid] > nums[left]
,说明mid的左侧是升序的; - 若
mid < nums[left]
,说明mid的右侧是升序的;
而我们通过这规律,就可以区分两段升序的数组,然后在对应的升序区间内,进行二分查找
,然后不断调整left和right的位置。
Tips
:在日常使用,数据量不多的情况下,可以直接用indexOf搜索。但是题目中要求时间复杂度为O(logn)
,那就只能使用二分查找了,因为indexOf是逐个遍历匹配,时间复杂度为 O(n)
> 思路:
-
第一步:基于二分法的思路,先找
mid
-
第二步:判断
mid
下标的值 和 first element(nums[left]) 的大小关系,确立mid所在的区间 -
第三步:分两部分讨论:
> 在左侧升序区间
中:
- 若
target >= left
同时target < mid
, 说明target在mid的左侧
,应该在[left, mid]
之间找,此时执行right = mid - 1
;否则target在mid的右侧,在[mid, right]
之间找, 此时left = mid + 1
;
> 在右侧升序区间
中:
- 若
target > mid
同时target <= right
, 说明target在mid的右侧
,应该在[mid, right]
之间找,此时执行left = mid + 1
;否则target在mid的左侧,应该在[left, mid]
之间找,此时right = mid -1
。
终止条件是,mid element === target
,结束
拓展知识
详细点击跳转 👉 < 算法基础 之 二分查找 >👈
三、解决方案:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
if(!Array.isArray(nums)) return -1
let left = 0, right = nums.length - 1
while (left <= right) {
const mid = Math.floor((right + left) / 2)
const curVal = nums[mid]
if(curVal == target) return mid
if(curVal >= nums[left]) {
if(target >= nums[left] && target < curVal) {
right = mid - 1
} else {
left = mid + 1
}
} else {
if(target <= nums[right] && target > curVal) {
left = mid + 1
} else {
right = mid - 1
}
}
}
return -1
};
往期内容 💨
🔥 < CSS小技巧:类似photoShop的混合模式(mix-blend-mode / background-blend-mode)使用 >