作者 l 码海
本文经授权转载自码海(ID:seaofcode)
一个优秀的程序员具备挺多特质的,比如好奇心,学习能力等,但在我看来一个优秀的程序员必须具备四项核心能力,哪四项,先卖个关子,程序员最喜欢说的话是「Talk is Cheap, show me your code」,那我们先来看一道很常见的面试题
如何快速定位IP对应的省份地址?
我们知道,每个省市都分配了一个 ip 段,如下
[202.102.133.0, 202.102.133.255] 山东东营市
[202.102.135.0, 202.102.136.255] 山东烟台
[202.102.156.34, 202.102.157.255] 山东青岛
[202.102.48.0, 202.102.48.255] 江苏宿迁
[202.102.49.15, 202.102.51.251] 江苏泰州
[202.102.56.0, 202.102.56.255] 江苏连云港
输入一个 ip 地址怎么做到秒级定位此 ip 所在的省市呢?
如图示:在百度上输入一个 ip 地址,能做到秒级展示其所属地,怎么做到的呢,背后用到了什么原理
这就引入了我们要谈的程序员需要具备的第一项能力: 抽象问题或者说数据建模的能力
所谓抽象问题或者说数据建模的能力,即能把一个问题抽象或归类为某种方案来解决,比如要实现负载均衡, 会想到一致性哈希算法,要实现最短路径,想到使用动态规划, 微服务下要保证服务可用引入降级机制等等,一句话就是把具体的问题抽象成到解决此问题背后的方法论,进而用相关的技术方案得以解决。
回归到如何快速定位 IP 对应的省份地址这道题来看,如果我们不具备抽象问题的能力,硬着头皮从头到尾把输入的ip 与所有区间段的 ip 都遍历对比一遍,然后判断它落到哪个区间,那么 ip 地址有 32 位,共有 2^32 个,约有 42.9 亿个,用暴力遍历法每查找一个 ip 最坏情况下要遍历约 42 亿次,这种方法显然是不可行的。
所以我们必须得把这个问题抽象为另一种可行的方法,即:二分查找, ip 地址查找怎么就跟二分查找扯上关系了,背后的逻辑是什么,我们一起来看看。
ip 地址不容易比较,那我们首先把 ip 地址转成整数,于是每个省市对应的 ip 地址区间就变成了整数区间,假设为如下区间
[1, 5]
[11, 15]
[16, 20]
[6, 10]
....
再以每个整数区间的起始数字对这些区间进行排序,排序后的区间如下
[1, 5]
[6, 10]
[11, 15]
[16, 20]
...
看到这些排序后的区间,想到了啥,二分查找就是在一组有序的数字中进行查找!是不是找到相似点了?
这里给没听过二分查找的读者简单普及下啥是二分查找,小时候可能我们都玩过猜字游戏,在纸面上写一个 1 到 100 的数字,比如 70,让对方猜,怎样猜才能猜最快。
首先猜 1 和 100 的中间数字 (1+ 100) / 2 = 50(取整)
50 < 70, 于是我们继续猜 50 和 100 的中间数字 (50+100) / 2 = 75
75 > 70,于是我们继续猜 50 和 75 的中间数字 (50+75) / 2 = 62
依次持续类似以上的步骤,不断地缩小范围,直至找到 70
总共只猜了 7 次,比起我们从 1 猜到 100 效率高了十几倍,如果被猜字的范围从一扩大到成百上千万,提升的效率是指数级的!二分查找也叫折半查找(注意上文中加粗的中间数字),仔细看上图,每查找一次,问题规模缩小一半,整体时间复杂度是O(logn),即使我们要在 42 亿的数字中查找数字,最多也只要查 32 次,所以采用二分查找对查找性能的提升无疑是巨大的!
二分查找是要在一堆有序的数字中精准地查找所要查找的数是否存在,而回过头来看已经排序好的以下 ip 段
[1, 5]
[6, 10]
[11, 15]
[16, 20]
...
我们要查找的是某个整数是否在一个有序数组的相邻两个数字的区间里,例如:取这些 ip 区间的起始地址组成一个数组 (1,6,11,16,....)(有序数组),如果我们要找的 ip 对应的整型为 14, 由于它在 [11,16) (11是闭区间,16是开区间) 之间,所以这个 ip 就落在 [11, 15] 这个 ip 区间,这样就找到了这个 ip 对应的省市了。
所以就由二分查找某个值是否存在转变成了查找某个值是否在有序数组中相邻的两个值之间了,这就引入了程序员要具备的第二层能力:举一反三或者说修改模型的能力
就像机器学习,现在其实有很多现成的模型可用,比如识别物的模型等等,我们需要的话可以直接拿来用,但是现有模型的准确率可能不是那么理想(比如只有80%),如果我们需要进一步地提升识别准确率,可能就需要对其参数进行进一步的调优,以进一步地优化模型,达到我们预期的值。
再比如当当网基于 Dubbo 的扩展版本开发的 Dubbox 也是由于原来的 Dubbo 功能不满足其团队需求而在其基础上修改扩展的。
回过头来看以上说的原来二分查找只是查找某个值是否存在,而我们现在要解决的问题是查找某个值是否在相邻的两个值之间,这本质是也是对模型的调优或修改,以进一步满足我们的要求。于是我们写下了如下代码
public static int bsearch(int[] a, int length, int value) {
int low = 0;
int high = length - 1;
while (low value) {
if (mid == 0) {
return -1;
}
if (a[mid-1] > 1),于是代码变成了
public static int bsearch(int[] a, int length, int value) throws Exception {
if (length 1);
if (a[mid] > value) {
if (mid == 0) {
return -1;
}
if (a[mid-1] 0) {
if (mid == 0) {
return -1;
}
if (a[mid-1].compareTo(value)
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?


微信扫码登录