数据结构与算法:16 | 二分查找(下):二分查找进阶

在这里插入图片描述

变体一:查找第一个值等于给定值的元素

在这里插入图片描述

int bSearch(vector<int> &vec, int n, int value){
    int beg = 0;
    int end = n - 1;
    while(beg <= end){
        int mid = beg + ((end - beg)>>1);
        if(vec[mid] > value)    end = mid -1;
        else if(vec[mid] < value)   beg = mid + 1;
        else {
			if(mid == 0 || vec[mid - 1] != value)	return mid;
            else end = mid - 1;
		}
    }
    return -1;
}

变体二:查找最后一个值等于给定值的元素

int bSearch(vector<int> &vec, int n, int value){
    int beg = 0;
    int end = n - 1;
    while(beg <= end){
        int mid = beg + ((end - beg)>>1);
        if(vec[mid] > value)    end = mid -1;
        else if(vec[mid] < value)   beg = mid + 1;
        else {
			if(mid == n-1 || vec[mid + 1] != value)	return mid;
            else beg = mid + 1;
		}
    }
    return -1;
}

变体三:查找第一个大于等于给定值的元素

int bSearch(vector<int> &vec, int n, int value){
    int beg = 0;
    int end = n - 1;
    while(beg <= end){
        int mid = beg + ((end - beg)>>1);
        if(vec[mid] >= value){
            if(mid == 0 || vec[mid-1] < value)  return mid;
            else    end = mid-1;
        }
        else 
            beg = mid + 1;
    }
    return -1;
}

变体四:查找最后一个小于等于给定值的元素

int bSearch(vector<int> &vec, int n, int value){
    int beg = 0;
    int end = n - 1;
    while(beg <= end){
        int mid = beg + ((end - beg)>>1);
        if(vec[mid] <= value){
            if(mid == n-1 || vec[mid+1] > value)  return mid;
            else    beg = mid+1;
        }
        else 
            end = mid - 1;
    }
    return -1;
}

解答开篇

如何快速定位出一个 IP 地址的归属地?

如果 IP 区间与归属地的对应关系不经常更新,可以先预处理这 12 万条数据,让其按照**起始 IP **从小到大排序。如何来排序呢?IP 地址可以转化为 32 位的整型数。所以,我们可以将起始地址,按照对应的整型值的大小关系,从小到大进行排序。

然后,这个问题就可以转化为第四种变形问题“在有序数组中,查找最后一个小于等于某个给定值的元素”了。

当要查询某个 IP 归属地时,可以先通过二分查找,找到最后一个起始 IP 小于等于这个 IP 的 IP 区间,然后,检查这个 IP 是否在这个 IP 区间内,如果在,取出对应的归属地显示;如果不在,就返回未查找到。

IP地址与无符号整数的转换_qq_32523711的博客-CSDN博客

百度面试题------将一个电分十进制的IP地址转换为一个32位的整数,要求一一对应

内容小结

上一节我说过,凡是用二分查找能解决的,绝大部分我们更倾向于用散列表或者二叉查找树。即便是二分查找在内存使用上更节省,但是毕竟内存如此紧缺的情况并不多。

实际上,上一节讲的求“值等于给定值”的二分查找确实不怎么会被用到,二分查找更适合用在“近似”查找问题,在这类问题上,二分查找的优势更加明显。

比如今天讲的几种变体问题,用其他数据结构,比如散列表、二叉树,比较难实现。变体的二分查找算法写起来非常烧脑,很容易因为细节处理不好而产生 Bug,这些容易出错的细节有:终止条件、区间上下界更新方法、返回值选择。

课后思考

我们今天讲的都是非常规的二分查找问题,今天的思考题也是一个非常规的二分查找问题。如果有序数组是一个循环有序数组,比如 4,5,6,1,2,3。针对这种情况,如何实现一个求“值等于给定值”的二分查找算法呢?

LeetCode第 33 题:搜索旋转排序数组(C++)_qq_32523711的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值