一文彻底搞懂二分查找

本文章视频版(点击跳转)

现在有一个问题,系统从 1-100 中随机生成一个数字,你每次猜一个数后,系统会告诉你大了、小了或者对了,请问你如何用最少次数猜中呢(思考一下)?

二分查找:区间折半对比查找,其中区间有序或有一定规律

假如,这个数是 25。

思路:首先我们明确初始区间【1,100】注意这里是闭区间, 然后我们区间折半,从中间数字猜即50( 这里去掉小数),与25进行对比,比25大,则缩小区间为【1,49】这里仍为闭区间。然后我们继续猜25(),正好等于系统生成的数25,停止猜数。

这里我们用了两次就猜中,而有时候数字可能并不是特别的巧,这里我们来分析二分查找的最坏情况,即时间复杂度。

二分查找每次都缩小搜索区间为原来的一半,那么对于一个区间长度为 n 的区间,我们至多只需 的次数即可查找完整个区间,即最坏的查找次数。

现在用计算机实现上述过程,代码:

int target = ?; // 这是随机的一个数
int left = 1, right = 100;
while (left <= right) {

  //等价于(left + right) / 2,这样写可以防止(left + right)过大而溢出
	int mid = left + (right - left) / 2;

	if (mid == target){ // 找到后退出
		break;
    }
   else if (mid > target) { // 大于目标数,缩小区间在 mid 的左边继续找
   	  right = mid - 1;
   }
   else if (mid < target) { // 小于目标数,缩小区间在 mid 的右边继续找
   	  left = mid + 1;
   }
}

现在又有一个问题,假如一个有序数组为【0,1,2,3,4,4,6,7,8,9】,如何最快找到4第一次出现的坐标(数组起始坐标为0)。

二分查找:区间折半对比查找,其中区间有序或有一定规律

首先明确初始区间【0,9】(数组坐标),第一次取中点 4,其坐标上的数恰巧等于 4,因为要找4第一次出现的坐标,所以缩小区间为【0,3】,在这区间中继续找。第二次取中点 1,其上为数为 1,缩小区间为【2,3】。第三次取中点 2,其上为 2,继续缩小区间为【3,3】,取中点 3,其上为 3,则这时为左端点为 4,即为 4 第一次出现的坐标。

现在用计算机实现上述过程,代码:

int arr[10] = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9}
int target = ?; // 目标数
int left = 0, int right = 9; // left 和 right 为左右边界坐标
while (left <= right) {
	int mid = left + (right - left) / 2;
   if (arr[mid] == target) { // 等于时缩小区间在 mid 的左边继续找
   		right = mid - 1;
   }
  	else if (arr[mid] > target) { // 大于时缩小区间在 mid 的左边继续找
		right = mid - 1;
    }
   else if (arr[mid] < target) { // 小于时缩小区间在 mid 的右边继续找
   	  left = mid + 1;
   }

}

最后一个问题,假如一个有序数组为【0,1,2,3,4,4,6,7,8,9】,如何最快找到 4 最后一次出现的坐标(数组起始坐标为 0)。

二分查找:区间折半对比查找,其中区间有序或有一定规律

首先明确初始区间【0,9】(数组坐标),第一次取中点 4,其坐标上的数恰巧等于4,因为要找4最后一次出现的坐标,所以缩小区间为【5,9】,在这区间中继续找。第二次取中点 7,其上为数为 7,缩小区间为【5,6】。第三次取中点 5,其上为 4,继续缩小区间为【6,6】,取中点 6,其上为 6,这时为左端点为 6,则 5(左端坐标减一)为4最后一次出现的坐标。

现在用计算机实现上述过程,代码:

int arr[10] = {0, 1, 2, 3, 4, 4, 6, 7, 8, 9} // 有序数组
int target = ?; // 目标数
int left = 0, int right = 9; // left 和 right 为左右边界坐标
while (left <= right) {
	int mid = left + (right - left) / 2;
   if (a[mid] == target) { // 等于时缩小区间在 mid 的左边继续找
   		left = mid + 1;
   }
  	else if (arr[mid] > target) { // 大于时缩小区间在 mid 的左边继续找
		right = mid - 1;
    }
   else if (arr[mid] < target) { // 小于时缩小区间在 mid 的右边继续找
   	  left = mid + 1;
   }


}

二分查找的核心思想:在某个有规律的区间中,找寻某个元素时,折半对比,缩小区间,重复操作,直至找到结果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

志尊威少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值