「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」
前言
力扣第八十一题 搜索旋转排序数组 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
一、思路
这一题与前面的三十三题,唯一的不同就是数组中可能会有重复值,所以基本的解题思路是差不多的,仍然使用的是二分法。
这一题的关键就是通过 target 与 nums[mid]、nums[left] 和 nums[right] 进行比较,从而判断 target 是否在 [0 ~ k] 的非递减区间内,或 target 是否在
[k ~ n] 的非递减区间内。
出现相同的值带来的影响就是,当 nums[mid] == nums[left] == nums[right] 时,无法判断 target 是在 [left, mid] 或 [mid, right] 中。所以,当出现
这种情况时,我们简单的将 left 和 right 都减一。
大致的实现步骤如下所示:
- 初始化值,
left = 0,right = len -1 - 使用
二分法进行取值,nums[mid]大致会出现以下几种情况
nums[left] <= nums[mid]说明左半边是非递减的,如果值在左半边,则丢弃右边。反之也是一样nums[left] <= nums[mid]说明右半边包含了[k ~ n]这一段,判断值是否在[k ~ n]这一段非递减区间上,如果在则丢弃左半边。如果不在,则丢弃右半边。
举个例子
此处以 nums = {3,1,2,2,2}, target =1 作为例子
left = 0, right = 4, mid = 2,因nums[left] > nums[mid],且值不在[k ~ n]中,故将right = mid -1 = 1left = 0, right = 1, mid = 0,此时nums[right] == target,故返回true
二、实现
实现代码
public boolean search(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return false;
}
int left = 0, right = len - 1;
while (left <= right) {
int mid = (left + right) / 2;
// 相等的情况
if (nums[mid] == target || nums[left] == target || nums[right] == target) {
return true;
}
// 特殊情况:缩小区间
if (nums[left] == nums[mid] && nums[mid] == nums[right]) {
++left;
--right;
} else if (nums[left] <= nums[mid]) { // 左边是递增的
if (nums[left] < target && target < nums[mid]) { // 值在左边
right = mid - 1;
} else {
left = mid + 1;
}
} else { // 该区间有[0 ~ k]
if (nums[mid] < target && target < nums[len - 1]) { // 判断是否在[0 ~ k] 上
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return false;
}
测试代码
public static void main(String[] args) {
int[] nums = {3,1,2,2,2};
int target = 1;
boolean flag = new Number81().search(nums, target);
System.out.println("test");
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~