算法(1)二分查找

1. 基本概念

  1. 优点:比较次数少,查找速度快
  2. 缺点:查找的必须为有序表
  3. 要求:必须使用顺序存储,关键字必须有序排列
  4. 时间复杂度:O(logn)

2. 二分查找分类


2.1 综述

假定要查找的关键字为target
代码中的查找队列均为int[],关键字以升序排列


2.2 查询是否存在target,返回值为boolean

//普通的二分查找:从一个数组中查找某个数是否存在,如果存在则返回true,不存在则返回false
public boolean targetExists(int[] nums, int target) {
	if( nums == null || nums.length == 0 ) return false;
	int l = 0, r = nums.length -1;
	while( l <= r ) {//是否有等号的关键在于,(l、r)与mid之间的关系
		int mid = l+((r-l)>>1);//使用传统的(l+r)>>1,可能会溢出。同时+的优先级高于>>
		if( nums[mid] == target ) return true;
		if( nums[mid] > target ) r = mid-1;
		else l = mid+1;
	}
	return false;
}

2.3 查询target第一次出现的下标,不存在则返回-1

//target第一次出现的下标,不存在则返回-1
public int firstTarget(int[] nums, int target) {
	if( nums == null || nums.length == 0 ) return -1;
	int l = 0, r = nums.length - 1;
	while( l < r ) {
		int mid = l+((r-l)>>1);
		if( nums[mid] == target ) r = mid;//由于这一步的存在,while条件不能是l<=r,否则可能会死循环
		else if( nums[mid] > target ) r = mid-1;
		else l = mid+1;
	}
	
	//对于l是否会越界的思考
	//如果l要越界,只有l=mid+1这一步才有这个可能性。
	//有两个条件:
	//1. while(l<r)表示,当前数组长度肯定至少为2
	//2. mid = l+((r-l)>>1)表示,当数组长度为偶数时,选择的是较小的中位数。如0,1,2,3,计算mid选择的是1而不是2
	//这两个条件下,mid+1肯定不会越界
	//相反,r可能会越界
	if( nums[l] == target) return l;
	return -1;
}

2.4 查询target最后一次出现的下标,不存在则返回-1

//target最后一次出现的下标,不存在则返回-1
public int lastTarget(int[] nums, int target) {
	if( nums == null || nums.length == 0 ) return -1;
	
	int l = 0, r = nums.length - 1;
	while( l < r ) {
		int mid = l + ((r-l+1)>>1);//可能会溢出,偶数个数时,选择第二个中位数
		if( nums[mid] == target ) l = mid;//要选择靠后中位数的原因就在于l=mid。如果选择的是前一个中位数,当[2,3],target=2时,会造成死循环
		else if( nums[mid] > target ) r = mid-1;
		else l = mid+1;
	}
	
	if( nums[r] == target ) return r;
	return -1;
}

2.5 查询小于target中最大数的下标,不存在则返回-1

public int lastLessThanTarget(int[] nums, int target) {
	if( nums == null || nums.length == 0 ) return -1;
	
	int l = 0, r = nums.length - 1;
	while( l < r ) {
		int mid = l + ((r-l+1)>>1);//可能会溢出
		if( nums[mid] == target ) r = mid-1;
		else if( target > nums[mid] ) r = mid-1;
		else l = mid;
	}
	
	//l和r都一样,因为最终都有l==r
	if( nums[l] < target ) return l;
	return -1;
}

2.6 查询大于target中最小数的下标,不存在则返回-1

//返回第一个大于target数的下标
public int firstGreaterThanTarget(int[] nums, int target) {
	if( nums == null || nums.length == 0 ) return -1;
	
	int l = 0, r = nums.length - 1;
	while( l < r ) {
		int mid = l + ((r-l)>>1);
		if( nums[mid] == target ) l = mid+1;
		else if( nums[mid] > target ) r = mid;
		else l = mid+1;
	}
	
	//选择l或者r都一样,因为最终肯定有l==r
	if( nums[l] > target ) return l;
	return -1;
}

3. 其他问题

  1. 给定数组长度(假设为n),问最多比较次数:二分查找的判定树是满二叉树,最多比较次数起始就是问节点数为n的完全二叉树的高度,即[log2n]取下整+1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值