算法基础-旋转有序数组的二分搜索

要求

  给定一个没有重复元素的旋转数组(它对应的原数组是有序的),求给定元素在旋转数组内的下标(不存在的返回-1),要求算法时间复杂度越小越好。

函数定义:int Search(int[] nums, int target)

例子:

有序数组{0,1,2,3,4,5,6,7}对应的旋转数组为{3,4,5,6,7,0,1,2}(左旋、右旋效果相同)。

  • 查找元素5,返回结果2;
  • 查找元素8,返回结果-1。

分析:可以轻易地想到遍历一遍O(n)时间可以得到结果,但是并不是最好的结果;利用有序的特点,很容易就联想到要用二分查找的方法,从而将时间复杂度降到O(logn)

但是通过旋转后的数组是两个有序的数组拼接在一起,如何利用有序这个特点结合二分法从而达到O(logn)的时间复杂度?

如果我们取中间一个数来看,那么在这个数的两边,则必然有一边是有序的,而被这个中间数分割后的另一边则是无序的一边,如图所示:

定义每次循环二分查找的中间数下标为mid,最左边的数字下标为left,最右边的数字的下标为right,则该问题可以通过循环下述三个步骤解决

1)如果mid=target,则返回mid

2)如果num[mid]<num[right],则表示右边子序列有序,这时候如果nums[mid]<target<=num[right]则left=mid+1;否则right = mid-1

3)除上述两种两种情况,则只能是左边子序列有序,这时候如果nums[mid]>target >=num[left]则right = mid-1;否则left= mid+1

循环控制条件是left <=right

参考代码:

public static int search(int[] nums, int target){
	int mid = nums.length/2;
	ind left = 0;
	int right = nums.length-1;
	while(left <= right){
		if(nums[mid] == target){
			return mid;
		}
		// 右边有序,则看是修改right的值还是修改left的值
		else if(nums[mid] < num[right]){
			// target如果落在右边这个有序的子序列范围内,则修改left=mid+1
			if(nums[mid] <target && target <= nums[right]){
			    left = mid+1;
			}else{
				right = mid -1;
			}
		}
		// 左边有序,则看是修改right的值还是修改left的值
		else{
			if(nums[left] <= target && target < nums[mid]){
				right = mid -1;
			}else{
				left = mid +1;
			}
		}
		mid = (left+right)/2;
	}
	
	return -1;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值