一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第29天,点击查看活动详情。
一、题目
整数数组 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
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/se… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、思路
双指针
- 这里的问题说是有一部分是无序的
- 还是定义指针left = 0, right = nums.length - 1
- while循环的判断条件是left < right
- 五种情况
- 第一种情况
- nums[left] === target 返回left
- 第二种情况
- nums[right] === target 返回 right
- 第三种和第四种可以合起来说,
- 看数组,左右区间,从中间看,要么左部分有序或者右区间有序
- 如果左区间有序且target < nums[right],那么right指针--
- 如果右区间有序且target > nums[left],那么left++
- 第五种情况,就是不存在的情况
- 那么就是小于左指针,大于右指针那么就返回-1
- 这时并没有完,本来按思路是完了的,但是要考虑长度为1的情况,
- 单独为这种情况做下处理
- 就是长度为1的情况下,如果值和target相等就返回0,否则返回-1
二分法
-
首先定义数组长度,左右区间和中间值 len = nums.length, left = 0, right = len - 1
-
首先判断特殊情况长度为1的时候,如果存在nums[0]等于target,那么返回0
-
while循环的条件是left <= right,重合的时候退出循环
-
三种情况
-
第一种
-
如果midNum 等于 target,那么返回mid
-
第二种和第三种情况
-
判断[0, mid]和[mid, right]哪边有序
-
如果[0, mid]有序,那么判断在当前有序的区间中
-
如果nums[0] <= target 且 target < midNum,那么可以缩小right
-
否则则增大left
-
不满足[0, mid]有序的情况
-
如果 midNum < target 且 target <= nums[len - 1]
-
那么左区间left 增加
-
否则 right 减小
-
如果都不满足条件
-
那么最后返回return -1
三、代码
双指针代码
let nums = [4,5,6,7,0,1,2], target = 0
// let nums = [1], target = 0
let search = function(nums, target) {
/**
* 思路双指针
* 这里的问题说是有一部分是无序的
* 还是定义指针left = 0, right = nums.length - 1
* while循环的判断条件是left < right
* 五种情况
* 第一种情况
* nums[left] === target 返回left
* 第二种情况
* nums[right] === target 返回 right
* 第三种和第四种可以合起来说,
* 看数组,左右区间,从中间看,要么左部分有序或者右区间有序
* 如果左区间有序且target < nums[right],那么right指针--
* 如果右区间有序且target > nums[left],那么left++
* 第五种情况,就是不存在的情况
* 那么就是小于左指针,大于右指针那么就返回-1
*
*
* 这时并没有完,本来按思路是完了的,但是要考虑长度为1的情况,
* 单独为这种情况做下处理
* 就是长度为1的情况下,如果值和target相等就返回0,否则返回-1
* */
let len = nums.length, left = 0 , right = len - 1
if(len == 1 && nums[0] == target){
return 0
}
while(left < right){
let leftNum = nums[left], rightNum = nums[right]
if(target < leftNum && target > rightNum){
return -1
}
if(target == leftNum){
return left
}
if(target == rightNum){
return right
}
if(left < right && target < rightNum){
right--
}else if(left < right && target > leftNum){
left++
}
}
return -1
}
二分查找
let nums = [4,5,6,7,0,1,2], target = 7
// let nums = [1], target = 0
// let nums = [3,1], target = 1
let search = function(nums, target) {
/**
* 二分法
* 首先定义数组长度,左右区间和中间值 len = nums.length, left = 0, right = len - 1
* 首先判断特殊情况长度为1的时候,如果存在nums[0]等于target,那么返回0
* while循环的条件是left <= right,重合的时候退出循环
* 三种情况
* 第一种
* 如果midNum 等于 target,那么返回mid
*
* 第二种和第三种情况
* 判断[0, mid]和[mid, right]哪边有序
* 如果[0, mid]有序,那么判断在当前有序的区间中
* 如果nums[0] <= target 且 target < midNum,那么可以缩小right
* 否则则增大left
* 不满足[0, mid]有序的情况
* 如果 midNum < target 且 target <= nums[len - 1]
* 那么左区间left 增加
* 否则 right 减小
* 如果都不满足条件
* 那么最后返回return -1
* */
let len = nums.length, left = 0 , right = len - 1
if(len == 1 && nums[0] == target){
return 0
}
while(left <= right) {
let mid = left + Math.floor((right - left)>>1)
let midNum = nums[mid]
if(midNum === target) {
return mid
}
if(nums[0]<= midNum) {
if(nums[0] <= target && target < midNum) {
right = mid - 1
} else {
left = mid + 1
}
} else {
if(midNum < target && target <= nums[len - 1]) {
left = mid + 1
} else {
right = mid - 1
}
}
}
return -1
}