![f2625fe8ad838d141cbe9f511bcba935.png](https://i-blog.csdnimg.cn/blog_migrate/d458c8e832edd3ad950d1a35c4c87faa.png)
/**
* create by: 睚雪
* description: 用二分查找
* 会出现几种情况
* 如果数组只有一个数 那么 left==fight 循环不走 直接输出left
* 1. 左值 < 中值, 中值 < 右值 :没有旋转,最小值在最左边,可以收缩右边界
* 2. 左值 > 中值, 中值 < 右值 :有旋转,最小值在左半边,可以收缩右边界
* 3. 左值 < 中值, 中值 > 右值 :有旋转,最小值在右半边,可以收缩左边界
* create time: 2020-4-27 20:43
* @params [nums]
* @return int
*/
public static int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}
![9b25ad6c62b2a13b82203026f2237380.png](https://i-blog.csdnimg.cn/blog_migrate/9ac210a0c9990317160896fc5a4f4ed0.jpeg)
解法一:
偷懒式解法 靠着上一题的算法找出最小值 以这个值进行分割将这个旋转数组分割成两个排序数组 进行二分搜索
public static int searchFindMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
public static int search(int[] nums, int target) {
if(nums.length==0){
return -1;
}
int right = nums.length-1;
int left = 0;
int min = searchFindMin(nums);//最小的位置的边界
if(target<=nums[right]){ //这个数字在最小值到最右边这个区间 不管数组怎么旋转从最小值到最右边一定是升序数组
left = findTarget2(nums,min,right,target);
}else{
if(min!=0&&nums[min-1]>=target){ //这个数字在另一个区间
left= findTarget2(nums,0,min-1,target);
}else{
return -1; //比所有值都大那么就只能是-1了
}
}
if(nums[left]==target){
return left;
}else {
return -1;
}
}
解法二:
直接在这个旋转数组里进行查找
大体上有两个状态
- left-mid之间还是一个排序数组没有干扰
- 正常的二分搜索
- left-mid之间有被破坏 要进一步分析target在哪边
- 就算是被破坏了但是mid到right一定是完整的
- 判断target是否在 mid-right之间 如果是缩小左半区
- 不在mid-right之间 砍掉右半区
public static int search2(int[] nums, int target) {
int right = nums.length-1;
int left = 0;
int mid = 0;
while(left<=right){ //这里的=于是考虑到数组只有一个元素省的多写一个判断
mid = left+(right-left)/2;
if(nums[mid]==target){ //当遍历到最后一个的时候因为计算公式是向下取整所以会是left
return mid;
}
if(nums[left]<=nums[mid]){ //先判断从left到mid这段数组是否是升序的 =是考虑到数组可能会有重复的选项
//正常的升序 再次判断 target在mid的左边还是右边
if (target >= nums[left] && target < nums[mid]) { //确认在左半边 缩小右半区
right = mid;
} else {
left = mid + 1;
}
}else{ //乱序了
if(target>nums[mid]&&target<=nums[right]){
//虽然乱了但是target的值是在乱了的那边也就是右边 缩小左半区
left = mid+1;
}else{
//不管怎么样从最小值到右半区肯定是没有他了 将右半区砍掉
right = mid;
}
}
}
return -1;
}