题目:
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6]
可能变为 [2,5,6,0,0,1,2]
)。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 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
进阶:
- 这是 搜索旋转排序数组 的延伸题目,本题中的
nums
可能包含重复元素。 - 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
思路:看了网上大神的代码,原文链接:https://blog.csdn.net/weixin_38823568/article/details/82491149。
以下代码的思路基本上是二分法的思路,由于数组中存在重复元素,所以开始时对数组的第一个元素进行处理。给比数组第一个元素小的元素加上一个值,使其成为递增数组,然后使用二分法。在题目中是一个升序排序的数组在某个点进行旋转,旋转后,数组中应该是存在两段排序好的数组。
代码:
class Solution {
public boolean search(int[] nums, int target) {
if(null == nums || 0 == nums.length)
return false;
int s = nums[0];
if(s == target)
return true;
for(int i = 0; i < nums.length && nums[i] == s; i++) //处理和第一个元素相等的元素,给它们设为一个负值
nums[i] = -0x3f3f3f3f;
int left = 0, right = nums.length-1, middle;
while(left <= right) {
middle = (left + right) >> 1;
if(nums[middle] == target)
return true;
if(rightVal(target, s) > rightVal(nums[middle], s)) //对小于第一个元素的值加上一个大值,使序列变为递增序列
left = middle+1;
else
right = middle-1;
}
return false;
}
private int rightVal(int x, int start) {
return x <= start ? x + 0x3f3f3f3f : x;
}
}
执行最快的代码:
执行最快的代码基本上也是二分法的思路
class Solution {
public boolean search(int[] nums,int target) {
int left = 0,right = nums.length-1;
while(left<=right) {
int mid = left + (right - left)/2;
if(nums[mid]==target || nums[left]==target || nums[right]==target)
return true;
if(nums[mid]==nums[left])
left ++;
else if(nums[mid]>nums[left]) {
if(target>nums[mid]) {
left = mid + 1;
}else {
if(target<nums[left])
left = mid + 1;
else
right = mid - 1;
}
}else {
if(target < nums[mid])
right = mid -1;
else {
if(target<nums[left])
left = mid + 1;
else
right = mid - 1;
}
}
}
return false;
}
}