题目链接
https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
题目描述
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,0,1,2,2,5,6]
might become [2,5,6,0,0,1,2]
).
You are given a target value to search. If found in the array return true, otherwise return false.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false
Follow up:
- This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.
- Would this affect the run-time complexity? How and why?
原本有一个有重复元素的升序列,然而把它分成两半,后面一半放到前面来了,比如:[4,5,6,7,0,1,2]
。现给定一个数target
,要求回答在这个数列中能否查找到target
。
分析
和上一版leetcode-33-Search in Rotated Sorted Array-二分查找很相似。
------------以下照抄了上一版的思路2333------------
比较直观地可以观察到,当我们把数组进行划分的时候,至少有一边是有序的——要么左边是有序的,要么右边是有序的(当然也有可能两边都是有序的)。
比如:[12,13,14,15,16,17,1,2,3,4]
的左半边[12,13,14,15,16]
是有序的,[17,1,2,3,4]
是无序的。
那么问题可以简化一下——
假如我们找到了有序的那一半,并且target就在这半的范围里,那么直接可以在这一半里搜索target了;否则就在另一半里进行搜索。
------------以上照抄了上一版的思路2333------------
但是!!!
存在重复元素的情况下,判断有序的条件需要更严苛一点,比如:[2,5,6,2,2,2,2,2]
被分割后,左半边照之前代码会被认为是有序的,因此需要做严格递增的判断。
代码
public boolean search(int[] nums, int target) {
int l = 0, r = nums.length - 1;
boolean ans = false;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) ans = true;
// 假如左边严格递增
if (nums[l] < nums[mid]) {
// ...且target在左半边的范围内,则对左半边进行搜索;否则搜索右半边。下同。
if (nums[l] <= target && target <= nums[mid]) {
r = mid;
} else {
l = mid + 1;
}
} else if (nums[l] > nums[mid]) {
if (nums[mid + 1] <= target && target <= nums[r]) {
l = mid + 1;
} else {
r = mid;
}
} else {
// 即出现像半边为[2,5,6,2]的情况,简单起见可以选择掐头或者去尾2333,反正都是重复的,但为了下标的连续就去掉第一个了_(:3
l++;
}
}
return ans;
}
吐槽
上一版主要有这样一个问题:
if (l == r && nums[l] == target) {
ans = l;
break;
}
这是针对只有一个元素的数组的,不过在这一版运行起来有点问题。
这一版改进了两点——
nums[l] < nums[mid]
用来判断严格递增- 需要对
nums[mid]
进行判断
因为第一点要求左半边数组的长度大于等于2,针对输入为[0,1]
这样的数据,直接被归到if-else
的最后一块,假如要查0是否存在,很显然就错过了答案。
所以还是得判断下nums[mid]
是否符合,哪怕不符合,也可以缩小数组范围。【非常生硬【迫真.jpg