面试总结之-查找算法分析

先说明一下~这里的查找主要指二分,不指DFS,BFS(那些我后面放到搜索部分)。 

查找的分析

         关于查找,最最最重要的是二分查找,也是这系列所有博客中最重要的部分,除了二分查找之外,还有平衡树,但是不会让你写平衡树= =!一般就是对于STL中set,map的使用,STL的东西一般也不会一定要你用,但是如果面试时什么都自己现场写的话肯定来不及,也容易出错,记住几个常用的数据结构的接口还是比较重要的,不懂的可以上去这里看看:http://www.cplusplus.com/reference/stl/,主要的是set, map, deque, list, vector, stack。

         先是最简单的二分查找,二话不说先上代码。

Code[0]:

int BinarySearch(int* a,int n,inttar){ //n是最后一个下标,tar是要找的数
 int i = 0, j = n;
 while(i<=j){
    int mid = i + (j-i)/2;
    if(a[mid] == tar) return mid;
    if(a[mid] > tar) j = mid-1;
    else i = mid+1;
 }
 return -1;
} 

         这是一个一般的BinarySearch:找到target就返回下标,找不到就返回-1,代码简单易懂,注意while循环条件有个等于号(不然你会漏了元素没有判断);但是考这个的可能性并不是很高,因为太简单了,一般会是一些变种,比如:找出大于等于target的最小值,小于等于target的最大值,大于target的最小值,小于target的最大值 = =!(绕晕了),不要急,后面一个个分析,据我所知,面试时要写前面几种二分,还很多人会写错边界条件的。

         一个例子就是:给定一个有序数组,问数字大小在[a,b]区间的有多少个。这个做法就是找出大于等于a的最小值的下标i,找出小于等于b的最大值下表j,返回j-i+1。如果问数字大小在区间(a,b),那上面找的值就没有“等于”了。

这四种二分看起来很麻烦,其实就是在一个框架下进行一点点改变就ok了。首先先给一个二分的框架:找大于等于target的最小下标。


Code[1]:

 

int BinarySearch(int* a,int n,inttar){
 int i = 0, j = n;
 while(i<=j){
    int mid = i + (j-i)/2;
    if(tar<=a[mid]) //等于往左走
      j = mid-1;
    else i = mid+1;
 }
 return i;  //返回i(i比j大)
}


         跟上面标准的二分来比,这里不在循环里面return了,放到了循环外面return一个i。注意这个框架,有两个地方可以进行修改,分别对应上面讲到的四种二分要求:

         1.      if(tar<=a[mid])  VS  if(tar<a[mid])

         2.      return i   VS   return j

         从1,2中各选一个可以对应上面的某个二分要求,比如上面代码,用了if(tar<=a[mid])和return i,就对应“找大于等于target的最小下标”。当然这个东西是不用死记的,想想某个数组,包含有多个target,比如0 1 2 3 3 3 4 5 6,你要找大于等于3的最小下标,那当a[mid]等于3时,你自然应该搜索左半部分(如果你搜索右半部分,得到的3的下标将不是最小下标),最后结束时,i,j分别应该指向 2和3,i>j,所以应该要返回i。如果不能取等号,就应该返回j。总结一下就是:

 

二分查找总结-jiacongxu

 

等于target往右搜 ( if(tar<=a[mid]) )

等于target往左搜 ( if(tar<a[mid]) )

返回小的坐标( return j )

     小于等于tar的最大值

小于tar的最大值

返回大的坐标( return i )

     大于target的最小值

 大于等于tar的最小值

这个表,记下来是没用的,在脑子里面跑一下二分的过程自然就明白什么情况应该用哪种二分,想象数组中有多个等于target的值。

 

         最后这个程序在找不到符合要求的数字时返回的下标是溢出的,如果返回了小的坐标(j),溢出情况是返回值为-1,如果是返回大的坐标(i),溢出情况的返回值是n。

如果觉得理解了,可以上去做做这个题,直接就是上面提到的二分的两种,点进去,不要回头查代码,一次AC吧:

Search for a Range

这题也基本一样,你可以认为简单点(其实就是一样的):

Search Insert Position

 

         接下来就是平衡树了。平衡树(具体说是红黑树)在STL里面的应用就是set和map(还有multiset和multimap),这东西做的事情跟二分查找差不多:用O(logn)的时间查找某个数或者查找不超过阈值的某个最大(最小)值,这些操作都跟上面的几种二分查找一一对应。但是平衡树的优势在于它是可以动态插入删除数据的(这个你用数组就不行了),缺点在于面试时你是没办法自己写一个平衡树的(要是面试官让你写个红黑树,你就把他吊起来打吧)。一个例子是:从数组中找和最接近给定值target的连续子数组(数组有负)。可以这样做:求出sum数组,对于sum[i],从[i+1,n-1]中查找一个最接近sum[i]+target的值,查找方法是,sum存到一个multiset里面(平衡树),每次i+1之后,把sum[i+1]从multiset中清除。时空复杂度O(nlogn)+O(n)。

         关于红黑树(或者其他平衡树)的介绍可以看看这个文章:教你透彻了解红黑树

         你只需要大概知道红黑树怎么个旋转法就好了,除非你自己感兴趣,不然不需要知道具体怎么代码实现,在面试时纸上写个红黑树太灭绝人性了。平衡树没什么好说的,主要因为面试不用写代码,只需要知道STL怎么用就好了。而怎么用STL就不说了,easy job,自己进去文章开头的那个连接看看自然就懂。上面给的两个题,当然你也可以用STL的set来坐坐看(杀鸡焉用牛刀~~),另外再给leetcode上面几道关于二分的题(不一定只能二分,但二分是一个可以接受的解):

Divide Two Integers                         二分答案~

Median of Two Sorted Arrays           这个题个人觉得很不好做,大家要是有什么特别浅显又不容易错的方法,请贡献个代码吧

Search in Rotated Sorted Array     这个貌似是面试高频题,不难搞,思考清楚边界条件,一次AC吧

Sqrt(x)                                                 这个题本身不难(尤其告诉你怎么做之后),不过它有一个把输入输出换成double的版本,思路一样,但是有一个很陷阱貌似很多人前赴后继的跳进去了,而且这个陷阱是不归路~~~

Search in Rotated Sorted Array II   这题放上来坑爹的,做做就知道怎么坑

 

其实讲起平衡树,总是跟哈希有千丝万缕关系,不过由于哈希太重要了,后面另起一篇讲了。他们之间的关系,看看STL里面,那些平衡树版本的数据结构时不时就蹦出一个哈希版本的(map 跟 hash_map)。最后加一句就是,红黑树跟有序数组这种差别(前面提到的动态和静态),在很多数据结构里面都体现了,比如预处理成数组的RMQ和线段树维护的RMQ,一般来说,面试时如果只需要静态的,你就写静态的,因为动态的不好写,然后也许面试官有个follow up问你动态怎么办,那你就聊聊动态的,尽量避免写代码了(虽然线段树比红黑树好写。。。。。)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值