已知存在一个按非降序排列的整数数组 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
可能包含重复元素。
- 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
前言
本篇题解基于「33. 搜索旋转排序数组的官方题解 」,请读者在阅读完该题解后再继续阅读本篇题解。
方法一:二分查找
思路
对于数组中有重复元素的情况,二分查找时可能会有 $a[l]=a[\textit{mid}]=a[r]$,此时无法判断区间 $[l,\textit{mid}]$ 和区间 $[\textit{mid}+1,r]$ 哪个是有序的。
例如 $\textit{nums}=[3,1,2,3,3,3,3]$,$\textit{target}=2$,首次二分时无法判断区间 $[0,3]$ 和区间 $[4,6]$ 哪个是有序的。
对于这种情况,我们只能将当前二分区间的左边界加一,右边界减一,然后在新区间上继续二分查找。
代码
[sol1-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Solution { public: bool search(vector<int> &nums, int target) { int n = nums.size(); if (n == 0) { return false; } if (n == 1) { return nums[0] == target; } int l = 0, r = n - 1; while (l <= r) { int mid = (l + r) / 2; if (nums[mid] == target) { return true; } if (nums[l] == nums[mid] && nums[mid] == nums[r]) { ++l; --r; } else if (nums[l] <= nums[mid]) { if (nums[l] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[n - 1]) { l = mid + 1; } else { r = mid - 1; } } } return false; } };
|
[sol1-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Solution { public boolean search(int[] nums, int target) { int n = nums.length; if (n == 0) { return false; } if (n == 1) { return nums[0] == target; } int l = 0, r = n - 1; while (l <= r) { int mid = (l + r) / 2; if (nums[mid] == target) { return true; } if (nums[l] == nums[mid] && nums[mid] == nums[r]) { ++l; --r; } else if (nums[l] <= nums[mid]) { if (nums[l] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[n - 1]) { l = mid + 1; } else { r = mid - 1; } } } return false; } }
|
[sol1-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| func search(nums []int, target int) bool { n := len(nums) if n == 0 { return false } if n == 1 { return nums[0] == target } l, r := 0, n-1 for l <= r { mid := (l + r) / 2 if nums[mid] == target { return true } if nums[l] == nums[mid] && nums[mid] == nums[r] { l++ r-- } else if nums[l] <= nums[mid] { if nums[l] <= target && target < nums[mid] { r = mid - 1 } else { l = mid + 1 } } else { if nums[mid] < target && target <= nums[n-1] { l = mid + 1 } else { r = mid - 1 } } } return false }
|
[sol1-Python3]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Solution: def search(self, nums: List[int], target: int) -> bool: if not nums: return False n = len(nums) if n == 1: return nums[0] == target l, r = 0, n - 1 while l <= r: mid = (l + r) // 2 if nums[mid] == target: return True if nums[l] == nums[mid] and nums[mid] == nums[r]: l += 1 r -= 1 elif nums[l] <= nums[mid]: if nums[l] <= target and target < nums[mid]: r = mid - 1 else: l = mid + 1 else: if nums[mid] < target and target <= nums[n - 1]: l = mid + 1 else: r = mid - 1 return False
|
[sol1-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| bool search(int* nums, int numsSize, int target) { if (numsSize == 0) { return false; } if (numsSize == 1) { return nums[0] == target; } int l = 0, r = numsSize - 1; while (l <= r) { int mid = (l + r) / 2; if (nums[mid] == target) { return true; } if (nums[l] == nums[mid] && nums[mid] == nums[r]) { ++l; --r; } else if (nums[l] <= nums[mid]) { if (nums[l] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[numsSize - 1]) { l = mid + 1; } else { r = mid - 1; } } } return false; }
|
[sol1-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| var search = function(nums, target) { const n = nums.length; if (n === 0) { return false; } if (n === 1) { return nums[0] === target; } let l = 0, r = n - 1; while (l <= r) { const mid = Math.floor((l + r) / 2); if (nums[mid] === target) { return true; } if (nums[l] === nums[mid] && nums[mid] === nums[r]) { ++l; --r; } else if (nums[l] <= nums[mid]) { if (nums[l] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[n - 1]) { l = mid + 1; } else { r = mid - 1; } } } return false; };
|
复杂度分析