1. 搜索旋转排序数组1
(1) 暴力
class Solution {
public int search(int[] nums, int target) {
for(int i = 0; i < nums.length; i++){
if(nums[i] == target)
return i;
}
return -1;
}
}
(2)二分
直接二分对于为排序数组来说是不行的(旋转后非有序数组)
class Solution {
public int search(int[] nums, int target) {
int left= 0, right = nums.length, mid = 0;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return -1;
}
}
但是,对于旋转数组,我们无法直接根据 nums[mid] 与 target 的大小关系来判断 target 是在 mid 的左边还是右边,因此需要「分段讨论」
class Solution {
public int search(int[] nums, int target) {
int left= 0, right = nums.length, mid = 0;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
}
// 先根据 nums[mid] 与 nums[left] 的关系判断 mid 是在左段还是右段
//nums[mid] > nums[left], 当前mid在右段(这里右段指:数组旋转后大的那一段)
if(nums[mid] > nums[left]){
// 再判断 target 是在 mid 的左边还是右边,从而调整左右边界 left 和 right
if(target >= nums[left] && target < nums[mid])
right = mid;
else//转去左段
left = mid + 1;
}else{ //当前mid在左段
//再判断 target 是在 mid 的左边还是右边,从而调整左右边界 left 和 right
if(target > nums[mid] && target <= nums[right - 1])
left= mid + 1;
else//转去右段
right = mid;
}
}
return -1;
}
}
2. 搜索旋转排序数组 II
但和 搜索旋转排序数组1 不同的是,本题元素并不唯一。
这意味着我们无法直接根据与 nums[0]nums[0] 的大小关系,将数组划分为两段,即无法通过「二分」来找到旋转点。
举个🌰,我们使用数据 [0,1,2,2,2,3,4,5] 来理解为什么不同的旋转点会导致「二段性丢失」:
(1)二分(恢复二段性)
class Solution {
public boolean search(int[] nums, int target) {
int len = nums.length;
int left = 0, right = len - 1;
// 恢复二段性
while (left < right && nums[0] == nums[right])
right--;
// 第一次二分,找旋转点
while (left < right) {
int mid = (left + right + 1)/ 2;
if (nums[mid] >= nums[0]) {
left = mid;
} else {
right = mid - 1;
}
}
int index = len;
if (nums[right] >= nums[0] && right + 1 < len)
index = right + 1;
// 第二次二分,找目标值
int ans = find(nums, 0, index - 1, target);
if (ans != -1)
return true;
ans = find(nums, index, len - 1, target);
return ans != -1;
}
public int find(int[] nums, int left, int right, int target) {
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
right = mid;
} else {
left = mid + 1;
}
}
return nums[right] == target ? right : -1;
}
}