博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面试官,您要的快排
阅读量:6275 次
发布时间:2019-06-22

本文共 2089 字,大约阅读时间需要 6 分钟。

今天看到 V2EX 上有人讨论 ,看来还是有很多人关心的。结合自己最近面试的经历,我可以明确的告诉大家,类似这种问题,只要你的工作经验小于 10 年,基本上逃不掉。劝大家不如抽点时间早做准备。

简式快排

面试中遇到问快排的,如上面那个帖子中的情况。你就可以上一份简式快排了,何谓简式?最短的代码表述快排的思想。

快排的思想,实质是分治法。基于什么来分?找一个支点来分,通常称之为 pivot, 而这个分的过程称之为 partition, 基于以上两点,我们用递归的方式描述快排:

void quicksort(int arr[], int l, int r) {    if (l < r) {        int pivot = partition(arr, l, r);        quicksort(arr, l, pivot-1);        quicksort(arr, pivot+1, r);    }}

如何?简单吧。有人说面试的时候手写快排,如果提前没有背下来的话,肯定歇菜。我不认为这样基础的算法是需要背的,上面这个递归,如此简洁,如此美,真的需要硬记?

有人说,这个好理解,关键在于 partition 如何实现。的确,partition 是快排的灵魂。CLRS 里采用了以尾巴为支点的策略,我在这里与其保持一致:

int partition(int arr[], int l, int r) {    int k = l, pivot = arr[r];    for (int i = l; i < r; ++i)        if (arr[i] <= pivot) std::swap(arr[i], arr[k++]);    std::swap(arr[k], arr[r]);    return k;}

这算法用白话说,就是从头到尾迭代,和支点比较,大的不管,小的换。换了才往后看。最后支点戳中间,算是分界线。

3,7,8,5,2,1,9,5,4

这么来一下,就成了:

3,2,1,4,7,8,9,5,5^^^^^ | ^^^^^^^^^

然后同样的手法分别解决两边,这样递归的解下去。

来份三明治

其实上面的那份,已经可以解决面试中的问题了。但其实有很大的缺陷,如当所有元素都相同的情况下,partition 将一直返回 r, 递归的深度高达 N,每一次递归中 partition 又循环 N 次,时间复杂度直接飙到了 O(N^2). 这显然非常的不值当。

于是我们觉得分两份太粗,分三份试试?

5 7 4 3 1 2 6 5 5

也来那么一下,成为:

4 3 1 2 5 5 5 7 6^^^^^^^ |   | ^^^

这就是三明治的原理了,左边是小于 pivot 的,中间是等于 pivot 的,右边是大于 pivot 的。中间部分不参与递归,分治的是两边。

我们需稍稍改变下 partition 的实现,显然我们这次希望返回的两个支点(左右边界):

// 3-way partitionstd::pair
partition(int arr[], int l, int r) { int k = l, p = r; for (int i = l; i < p; ) if (arr[i] < arr[r]) std::swap(arr[i++], arr[k++]); else if (arr[i] == arr[r]) std::swap(arr[i], arr[--p]); else ++i; // move pivots to centre int m = std::min(p-k, r-p+1); for (int i = 0; i < m; ++i) std::swap(arr[k+i], arr[r-i]); return std::make_pair(k, r-p+k);}

quicksort 也需要稍稍改变一点:

void quicksort(int arr[], int l, int r) {    if (l < r) {        auto pivot = partition(arr, l, r);        quicksort(arr, l, pivot.first-1);        quicksort(arr, pivot.second+1, r);    }}

如果在遇到全部元素相同的情况,时间复杂度成功的减少到 O(N). 算是一个突破吧。

东北乱炖

其实 CLRS 随后还提到了以随机位置为 pivot 的思路,我称之为东北乱炖。那是只针对 pivot 选取的改变,基于上述代码,改造起来是非常容易的。这里就不做过多实现,留作感兴趣者自己练习吧。


上述三道菜,基本能够解决面试中可能遇到的种种情况了。让面试官吃饱,很有必要~

转载地址:http://rrgpa.baihongyu.com/

你可能感兴趣的文章
js 面试题
查看>>
sqoop数据迁移(基于Hadoop和关系数据库服务器之间传送数据)
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
Javascript 中的 Array 操作
查看>>
java中包容易出现的错误及权限问题
查看>>
AngularJS之初级Route【一】(六)
查看>>
服务器硬件问题整理的一点总结
查看>>
SAP S/4HANA Cloud: Revolutionizing the Next Generation of Cloud ERP
查看>>
Mellanox公司计划利用系统芯片提升存储产品速度
查看>>
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>
Oracle数据库的备份方法
查看>>
Selenium 自动登录考勤系统
查看>>
关于如何以编程的方式执行TestNG
查看>>
智能照明造福千家万户 家居智能不再是梦
查看>>
物联网如何跳出“看起来很美”?
查看>>
浅谈MySQL 数据库性能优化
查看>>
《UNIX/Linux 系统管理技术手册(第四版)》——1.10 其他的权威文档
查看>>
灵动空间 创享生活
查看>>
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.6 UDP回射客户程序:dg_cli函数...
查看>>