leetcode第33题-搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:

输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例 2:

输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

Java默认模版:

class Solution {
    public int search(int[] nums, int target) {
        
    }
}

答案:
解题思路:
此题考的是循环有序数组,循环有序数组定义为:
在这里插入图片描述
性质:

1.将一个循环有序数组一分为二,一定得到一个有序数组和另一个循环有序数组
2.长度不超过2的循环有序数组其实就是有序数组。

所以通过将题目中的数组一分为二一定能得到一个有序数组和另一个循环有序数组 ,如果搜索目标在有序数组那很好说,直接调用binarySearch方法找到,如果在另一个循环有序数组,那就递归用classifiedSearch方法分类搜索。那怎么判断搜索目标在哪里呢:

由题设可以推出:nums[low]>nums[high],而对于nums[mid]来说要么:nums[low]<=nums[mid],要么:nums[mid]<=nums[high]

所以核心代码如下:

if(nums[low]<=nums[mid]) {//说明[low,mid]单调递增
	if(nums[low]<=target&&target<nums[mid]) {//target在单调递增区间就二分法搜索
		return binarySearch(nums, low, mid-1, target);
	}else {//不在单调递增区间(即[low,mid])就肯定在子循环有序数组,子循环有序数组递归处理,又回到这个方法处理
		return classifiedSearch(nums, mid+1, high, target);
	}
}else {//nums[mid]<=nums[high],说明[mid,high]单调递增
	if(nums[mid]<target&&target<=nums[high]) {//target在单调递增区间就二分法搜索
		return binarySearch(nums, mid+1, high, target);
	}else {//不在单调递增区间(即[mid,high])就肯定在子循环有序数组,子循环有序数组递归处理,又回到这个方法处理
		return classifiedSearch(nums, low, mid-1, target);
	}
}
class Solution {
	//测试
	public static void main(String[] args) {
		Solution s=new Solution ();
		/*Scanner sc=new Scanner(System.in);
		String s = sc.nextLine();*/
		int[] nums=new int[]{9,0,2,7,8};
		System.out.println(s.search(nums, 3));
	}
	
	//题目中约定的入口
	public int search(int[] nums, int target) {
		return classifiedSearch(nums,0,nums.length-1,target);
    }
	
	//分类搜索,在这里划分各种情况,处理的是循环有序数组
	public int classifiedSearch(int[] nums,int low,int high,int target){
		if(low>high) {
			return -1;//处理[],也就是数组为空的情况,测试案例里有这种情况
		}else{//low==high||low<high
			int mid=(low+high)/2;
			//接下来就是判断nums[low]、nums[high]、nums[mid]和target的大小关系了
			if(nums[mid]==target)return mid;
			if(nums[low]<=nums[mid]) {//说明[low,mid]单调递增
				if(nums[low]<=target&&target<nums[mid]) {//target在单调递增区间就二分法搜索
					return binarySearch(nums, low, mid-1, target);
				}else {//不在单调递增区间(即[low,mid])就肯定在子循环有序数组,子循环有序数组递归处理,又回到这个方法处理
					return classifiedSearch(nums, mid+1, high, target);
				}
			}else {//nums[mid]<=nums[high],说明[mid,high]单调递增
				if(nums[mid]<target&&target<=nums[high]) {//target在单调递增区间就二分法搜索
					return binarySearch(nums, mid+1, high, target);
				}else {//不在单调递增区间(即[mid,high])就肯定在子循环有序数组,子循环有序数组递归处理,又回到这个方法处理
					return classifiedSearch(nums, low, mid-1, target);
				}
			}
		}
	}
	
	//单纯的二分法搜索,搜索范围包括起始下标和结束下标,一旦进入该方法的运行,该方法的返回值就是程序结果,未找到返回-1
    public int binarySearch(int[] nums,int low,int high,int target){
    	if(low>high||target<nums[low]||target>nums[high])return -1;//找到最后了没找到或者是不可能找到的情况
    	int mid=(low+high)/2;
    	if(nums[mid]==target) {
    		return mid;
    	}else if(nums[mid]<target) {
    		return binarySearch(nums, mid+1, high, target);//右边二分法搜索
    	}else {//nums[mid]>target
    		return binarySearch(nums, low, mid-1, target);//左边二分法搜索
    	}
    }

}

猜你喜欢

转载自blog.csdn.net/qq_22771739/article/details/86592396
今日推荐