LeetCode解题 81:Search in Rotated Sorted Array II
Problem 81: Search in Rotated Sorted Array II [Medium]
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?
来源:LeetCode
解题思路
与题解33:Search in Rotated Sorted Array类似。需要多考虑一种两个边界相等的情况,采用的办法是进行两次二分查找。
- 基本思路是利用二分查找,除了边界相等的情况,其余每层递归都能排除掉一半的数值。
- 难点在于条件判断,需要考虑要查找的
target
会不会因为排序数组的旋转而不在原本二分查找的那半段范围。为了方便说明,将头尾相接处称为断崖
,二分点下标称为p
,以下为需要分类讨论的情况:
a. 假设nums[p] < target
,说明目标值较大,正常情况下需要查找数组的右半部分,此时应有nums[right] > target
,需要查找p+1 ~ right-1
;
b. 当nums[right] < target
时,与正常情况不同,是需要讨论的重点。按断崖
所在的位置进行分类讨论。
b1. 寻找断崖
所处位置的方法是比较nums[right]
与nums[p]
的值,如果nums[right] < nums[p]
,则说明断崖
在p ~ right
之间,即最大的尾部处于这之间,要找的目标值比nums[p]
大,就可以在p+1 ~ right-1
之间查找。(例如在[4,5,6,7,8,9,1,2,3]中寻找9的第一次二分查找。)
b2. 如果nums[right] > nums[p]
,则说明p ~ right
之间是严格升序的,断崖
应该在left ~ p
之间,因此既比nums[p]
大又比nums[right]
大的目标值就应该在left ~ p-1
之间查找。(例如在[7,8,9,1,2,3,4,5,6]中寻找9的第一次二分查找。)
b3. 如果nums[right] = nums[p]
,那么无法判断出断崖
在left ~ p
([7,8,9,1,2,2,2,2,2]中找9)还是在p ~ right
([2,2,2,2,2,3,9,1,2]中找9),因为都有可能。这种情况下,需要对两半部分都进行二分查找,只有两边都返回false,才能证明数组中不存在target
。
c. 上述数值比较过程中如果有正好相等的情况则之间返回下标即可。如果有left > right
的情况则说明查找失败,返回false。 - 数组个数为0或仅剩1个数且不为
target
时直接返回false。
极端情况下复杂度有可能为 O ( n ) O(n) O(n)。
要点:二分查找
、条件判断
Solution (Java)
class Solution {
public boolean search(int[] nums, int target) {
int N = nums.length;
if(N == 0) return false;
return partSearch(nums, 0, N-1, target);
}
private boolean partSearch(int[] nums, int left, int right, int target){
if(left > right) return false;
if(left == right && nums[left] != target) return false;
int p = (left + right) / 2;
int nextl, nextr;
if(nums[p] == target){
return true;
}
else if(nums[p] < target){
if(nums[right] == target){
return true;
}
else if(nums[right] > target){
return partSearch(nums, p+1, right-1, target);
}
else{
if(nums[right] < nums[p]){
// 断崖在p~right之间
return partSearch(nums, p+1, right-1, target);
}
else if(nums[right] > nums[p]){
// 断崖在另半部分
return partSearch(nums, left, p-1, target);
}
else{
// 不能确定断崖位置,两半部分都要试
return partSearch(nums, left, p-1, target) || partSearch(nums, p+1, right-1, target);
}
}
}
else{
if(nums[left] == target){
return true;
}
else if(nums[left] < target){
return partSearch(nums, left+1, p-1, target);
}
else{
if(nums[left] > nums[p]){
// 断崖在left~p之间
return partSearch(nums, left+1, p-1, target);
}
else if(nums[left] < nums[p]){
// 断崖在另半部分
return partSearch(nums, p+1, right, target);
}
else{
// 不能确定断崖位置,两半部分都要试
return partSearch(nums, left+1, p-1, target) || partSearch(nums, p+1, right, target);
}
}
}
}
}