Skip to main content

搜索旋转排序数组-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++ 即可, 相当于去掉一个重复的干扰项.

/**
* @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
}

复杂度分析

时间复杂度: 因为增加了一次跳过判断操作, 因此循环会完全走一趟, 时间复杂度为 O(n)

空间复杂度: O(1), 只需要常数级别的空间存放变量.