33. 搜索旋转排序数组
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/submissions/
- 有序 查找 往二分查找上靠
- 虽然该数组被旋转导致整体无序,但从中间截断后至少有一半仍然是有序的
- 注意等号
从mid处划分,至少有一半是有序的。如果target在有序部分的区间内,可使用二分查找进行查找,如果没有找到直接返回-1。但如果target不在有序部分的区间内,并不能直接得出没有找到target的结论,因为有可能被旋转到了无序的区间。
每次在有序区间里找target,如果找到返回,如果没有找到,继续把无序区间一分为二,然后在新的有序区间寻找。
package binSearch; public class search_33 { public int search(int[] nums, int target) { int left = 0; int right = nums.length-1; int mid = (left+right)/2; while (left<=right) { mid = (left+right)/2; //左边有序 if (nums[mid]>nums[left]){ //先在有序区间里找 //目标值在有序范围内 if (target<=nums[mid] && target>=nums[left]){ return binSea(nums, left, mid, target); } //有序区间没有再去无序区间找 left = mid+1; }else { //右边有序 if (target>nums[mid]&&target<nums[right]){ return binSea(nums,mid,right,target); } right=mid-1; } } return -1; } public int binSea(int[]nums,int left,int right,int target){ int mid; while (left<=right){ mid = (left+right)/2; if (nums[mid]==target){ return mid; }else if (nums[mid]>target){ right = mid-1; }else { left = mid+1; } } return -1; } public static void main(String[] args) { int[] arr = {4, 5, 6, 7, 0, 1, 2}; int target = 9; search_33 fun = new search_33(); int result = fun.search(arr, target); System.out.println(result); } }
旋转数组还有一种变体,即数组中可能存在重复的值。此时就不能根据mid与左右端点的值来判断左区间和右区间是否是有序的,例如 1 3 1 1 1 1,此时mid为1,mid==left,但左区间并不是有序的。为此,当mid==left的时候,无法判断左右区间的有序性,故不能对原始数组进行折半,搜索数组的长度只能减少1。
class Solution { public boolean search(int[] nums, int target) { int left = 0; int right = nums.length-1; int mid = (left+right)/2; while (left<=right) { mid = (left+right)/2; if (nums[mid]==target){ return true; } //左边有序 if (nums[mid]>nums[left]){ //先在有序区间里找 //目标值在有序范围内 if (target<=nums[mid] && target>=nums[left]){ return binSea(nums, left, mid, target)==-1?false:true; } //有序区间没有再去无序区间找 left = mid+1; }else if (nums[mid]<nums[right]){ //右边有序 if (target>=nums[mid]&&target<=nums[right]){ return binSea(nums,mid,right,target)==-1?false:true; } right=mid-1; }else { //无法判断有序性,不能对数组进行折半操作 if (nums[left]==nums[mid]){ left++; }else { right--; } } } return false; } public int binSea(int[]nums,int left,int right,int target){ int mid; while (left<=right){ mid = (left+right)/2; if (nums[mid]==target){ return mid; }else if (nums[mid]>target){ right = mid-1; }else { left = mid+1; } } return -1; } }