现在有一个问题,系统从 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;
}
}
二分查找的核心思想:在某个有规律的区间中,找寻某个元素时,折半对比,缩小区间,重复操作,直至找到结果。