81. 搜索旋转排序数组 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 = [2,5,6,0,0,1,2], target = 0
输出: true
示例 2:
输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false
解题思路:这题的意思就是将一个升序的数组按照某个下标旋转,旋转之后其实就是两个升序的数组data1,data2,data1的最小值大于data2的最大值,因为二分算法的要求是有序数组,所以当target在data1里,且中间值nums[m]大于target,此时target在data[0]和data1[m]之间,data[0]-data[m]是升序数组满足二分算法,当target在data2里,且nums[m] 小于target时,nums[m]-data2也是一段升序数组符合二分算法,因为旋转数组的两端值可能否相等,所以如果两端值不等于target的话可以都消掉,这样左端值肯定大于右端值,方便去范围,代码如下:
var search = function(nums, target) {
//判断两端值是否相等
if(nums[0] == target || nums[nums.length - 1] == target) return true;
let l = 0,r = nums.length - 1,m;
//去掉左端与右端相等的值
while(nums[l] == nums[0] && nums[l] == nums[r] && l < nums.length) l ++;
//去掉右端与左端的值
while(nums[r] == nums[0] && r >= 0) r --;
//保存左端值和右端值
let head = nums[l],tail = nums[r];
while(l <= r){
m = (l + r) >> 1;
if(nums[m] == target) return true;
//当中间值在小的升序数组里时,判断是否在升序数组,
if(nums[m] <= tail){
if(nums[m] < target && target <= tail) l = m + 1;
else r = m - 1;
} else {
//在右边数组的时候判断,target是否在升序数组里
if(nums[m] > target && target >= head) r = m - 1;
else l = m + 1;
}
}
return false;
};