「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战」。
题目
链接:leetcode-cn.com/problems/se…
已知存在一个按非降序排列的整数数组 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,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
示例 1:
**输入:**nums = [2,5,6,0,0,1,2], target = 0
**输出:**true
示例 2:
**输入:**nums = [2,5,6,0,0,1,2], target = 3
**输出:**false
提示:
1 <= nums.length <= 5000-104 <= nums[i] <= 104- 题目数据保证
nums在预先未知的某个下标上进行了旋转 -104 <= target <= 104
进阶:
- 这是 搜索旋转排序数组 的延伸题目,本题中的
nums可能包含重复元素。 - 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
解题思路
思路1
(1).low,high取中间值,如果跟给定的元素相等,那就找到了返回true。
(2).不等的话判断哪半边数组有序,在有序的一边判断被查找的元素是否在有序数组里面(注意左右区间),缩小查询范围,更新low,high。
循环退出条件 low <= high
这也是#33题的思路,但是这道题可能有重复元素,即nums[low] == nums[mid],这时候需在(2)之前将low递增后再比较(排除掉这个重复的元素,查询范围缩小1)
注意:while里面嵌套while不行,会顺序往下执行。我们期待的是low++,后面不要执行,使用if~continue
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {boolean} 59-5
*/
var search = function(nums, target) {
var low = 0
var high = nums.length - 1
while(low <= high){
console.log('顶')
var mid = Math.floor(low + (high - low)/2)
if(nums[mid] == target) {
return true
}
console.log('前',low,'mid',mid)
if(nums[low] == nums[mid]){
low++
continue
} // 前 0;前 1;后 1
// while(nums[low] == nums[mid] && nums[low + 1] == nums[low]) {
// low = low+1
// }
console.log('后',low,'mid',mid)
if(nums[low] <= nums[mid]){ //左边有序
if(target >= nums[low] && target < nums[mid]){
high = mid -1
}else {
low = mid + 1
}
}else {
if(target <= nums[high] && target > nums[mid]) {
low = mid + 1
}else {
high = mid - 1
}
}
}
return false
};
思路2
因为是旋转过的,所以找到旋转的位置,即第一个 nums[i] < nums[i \- 1] 的位置,然后对左右两侧执行二分查找即可,返回左右两侧的或的结果
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {boolean}
*/
var search = function(nums, target) {
const length = nums.length;
if(length === 1) {
return nums[0] === target;
}
let res;
let mid = 0;
for(let i = 0; i < length; i++) {
if(nums[i] < nums[i - 1]) {
mid = i;
break;
}
}
const helper = function(l, r) {
if(l > r) {
return false;
}
let m = Math.round((l + r) / 2);
if(nums[m] === target) {
return true;
} else if(nums[m] < target) {
return helper(m + 1, r);
} else {
return helper(l, m - 1);
}
}
const left = helper(0, mid - 1);
const right = helper(mid, length - 1);
res = left || right;
return res;
};