搜索旋转排序数组-ii
题目
已知存在一个按非降序排列的整数数组 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.length <= 5000
-10⁴ <= nums[i] <= 10⁴
- 题目数据保证
nums
在预先未知的某个下标进行了旋转 -10⁴ <= target <= 10⁴
进阶:
- 本题为 33.搜索旋转排序数组 的扩展, 在此基础上的
nums
可能包含重复元素. - 这会影响到程序的时间复杂度吗? 会有怎样的影响, 为什么?
示例
输入: nums = [2, 5, 6, 0, 0, 1, 2], target = 0
输出: true
输入: nums = [1, 0, 1, 1, 1], target = 0
输出: true
题解
本题额外关注的就是类似 nums = [1, 0, 1, 1, 1]
这种情况, 此时 nums[mid]
跟 nums[left]
相 等, 分不清到底是前面有序还是后面有序, 因此让 left++
即可, 相当于去掉一个重复的干扰项.
- JavaScript
- Rust
/**
* @param {number[]} nums
* @param {number} target
* @return {boolean}
*/
var search = function (nums, target) {
let left = 0
let right = nums.length - 1
while (left <= right) {
const mid = (left + (right - left) / 2) | 0
if (nums[mid] === target) return true
// 去掉重复项
if (nums[left] === nums[mid]) {
left++
continue
}
if (nums[left] <= nums[mid]) {
if (nums[left] <= target && target < nums[mid]) {
right = mid - 1
} else {
left = mid + 1
}
} else {
if (nums[mid] < target && target <= nums[right]) {
left = mid + 1
} else {
right = mid - 1
}
}
}
return false
}
pub fn search(nums: Vec<i32>, target: i32) -> bool {
let mut left = 0;
let mut right = nums.len() - 1;
while left <= right {
let mid = (left + right) / 2;
if nums[mid] == target {
return true;
}
if nums[left] == nums[mid] {
left += 1;
continue;
}
if nums[left] <= nums[mid] {
if nums[left] <= target && target < nums[mid] {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if nums[mid] < target && target <= nums[right] {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
false
}
复杂度分析
时间复杂度: 因为增加了一次跳过判断操作, 因此循环会完全走一趟, 时间复杂度为 O(n)
空间复杂度: O(1)
, 只需要常数级别的空间存放变量.