LeetCode题目:搜索旋转排序数组

题目描述:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

这个题目要求算法时间复杂度必须是 O(log n) 级别,其实就是间接地要求使用二分法解题。

首先来复习一下二分法:
设定一个低序坐标low指向有序数组的第一个元素,一个高序坐标high指向有序数组的最后一个元素,middle指向low和high的中间位置,即middle=low+(low+high)/2,如果middle位置的数大于target的数,说明target的数在low和middle之间的位置,把(middle-1)设为新的high;如果middle位置的数小于target的数,说明target的数在middle和high之间的位置,把(middle+1)设为新的low。通过这样的一步就能把长度缩短一半,重复这一步,如果找到middle位置的数就是target,就直接返回middle;如果当high<low时仍未找到target,说明数组中不存在target。

代码(Java):

public static int binarySearch(int[] nums, int target) {
		int ans = -1;
		int low = 0;
		int high = nums.length-1;
		int middle = 0;
		while(high>=low) {
			middle = low + (high - low)/2;
			if(nums[middle]==target) {
				ans = middle;
			}
			if(nums[middle]>=target) {
				high = middle - 1;
			}else if (nums[middle]<=target) {
				low = middle + 1;
			}
		}
		return ans;
	}

再看这个题目,其实很容易被旋转之后的数组迷惑。同样地,可以设置low,high,middle来将数组分成两个部分,其中一个部分必然是有序的,另一个部分是无序的,target在不在无序的部分不好判断,但是在不在有序的部分里面还是好判断的(假设数组里面有target),只要target大于有序部分的第一个数,而且小于有序部分的最后一个数,就说明target在有序的部分里面,否则,target就是在无序的部分,再根据现实情况,执行high = middle-1或者low = middle+1;执行第二次循环的时候,再次根据middle分割数组,同样是分为有序和无序的两个部分,和前面的操作一样。这样就和普通的二分法联系起来了。

代码(Java):

public class doingmyself {
	public static void main(String[] args) {
		int[] nums = new int[] {4,5,6,7,0,1,2};
		System.out.println(search(nums, 3));
	}
	
	public static int search(int[] nums, int target) {
		int low = 0;  //low表示二分法里面目标值所在范围的头坐标
		int high = nums.length-1;  //high表示二分法里面目标所在范围的尾坐标
		int middle = 0;  //用mid表示数组中间那个数的坐标
		while(low<=high) {
			middle = low + (high-low)/2;  //同样第二次执行循环的时候,也是将剩下的范围劈成两部分,一部分是有序的,另一部分是无序的
			if(target == nums[middle]) {
				return middle;
			}
			if(nums[low]<=nums[middle]) { //表示第一部分是有序的 
				if(target<=nums[middle] && target>=nums[low]) {  //表示目标值在有序的这部分
					high = middle-1;
				}else {  //表示目标在另一部分
					low = middle+1;
				}
			}else {  //第二部分是有序的
				if(target>=nums[middle] && target<=nums[high]) {  //表示目标值在有序的这部分
					low = middle+1;
				}else {  //表示目标在另一部分
					high = middle-1;
				}
			}
		}
		
		return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值