快排时间复杂度_手撕面试官:快排应用寻找第k小的数

    正在找工作的猿六凯在投出无数份简历后,准备打开电脑看会电影放松下。突然接到面试官的电话,急忙跑到厕所接听。

d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

小猿同学,看你的简历说算法掌握的比较扎实,我来给你出道算法题。

d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

我们有一个无序的,没有重复元素的数组,现在我们需要找出第k小的数字。

d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

比如我们的无序数组 7 3 5 1 6。需要找出第3小数。我们可以看出来,1是第一小的数,3是第二小的数,5是第三小的数。5就是我们要找的。

猿六凯

这个很简单呀,假设我们的数组是a,把数组排下序,然后a[k-1]就是我们要找的元素。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

排序的时间复杂度是O(nlogn),取元素的时间复杂度是O(1),所以我们的总时间复杂度是O(nlogn)。

0624f7760c61ce3366cb06c43d0ca74c.png d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

有没有其他的方法,比如用用快排的思想。

猿六凯

快排的思想??恩,我想想。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

快排的思想是分治,每次把数组分成两部分,左边部元素全都小于等于右边元素。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

我们要找第k小的数,这个数字要么在分开的数组左边,要么在右边。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

如果左边数组元素个数大于等于k,那么第k小的元素就在左边,我们在左边数组中找第k小的元素就可以。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

如果左边数组元素个数小于k,那么第k小的元素就在右边。假设我们左边数组右x个元素,我们在右边数组中找第k-x小的元素就可以。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

这样就能把寻找的范围一直缩小。直到最后,我们就在某个为1的范围内找第一小的数,这个时候,这个元素就是我们要找的元素了。

0624f7760c61ce3366cb06c43d0ca74c.png d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

恩,你手动模拟下7 3 5 1 6 找出第3小数字的过程。

猿六凯

我以30年单手手速化了下面动图。

0624f7760c61ce3366cb06c43d0ca74c.png 5a11d7288d1a7ca30646944e25cdcbeb.gif d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

恩,写下代码吧。

#include using namespace std;const int N = 100010;int a[N];int find(int a[], int l, int r, int k){    if(l == r && k == 1) return a[l];        int x = a[(l + r) >> 1];    int i = l - 1, j = r + 1;    while(i < j){        while(a[++i] < x);        while(a[--j] > x);        if(i < j ) swap(a[i], a[j]);    }            if(j- l + 1 >= k ) return find(a, l, j, k);    return find(a, j + 1, r, k - j + l - 1);    }int main(){    int n, k;    cin >> n >> k;    if(k > n) return -1;    for(int i = 0; i < n; i++){        cin>>a[i];    }    cout << find(a, 0, n-1, k);    return 0;}
d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

分析下时间复杂度和空间复杂度。

猿六凯

时间上,我们花费的是不断将搜寻范围缩小。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

在最好情况下,每次能将搜寻范围减少到原来的一般。所以第一次缩小范围花费的是O(n),第二次缩小范围花费的是O(n/2),第三次缩小范围花费的是O(n/4)。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

直到最后搜寻范围为1,我们就找到了答案。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

所以时间复杂度是:O(n)+O(n/2^1)+O(n/2^2)+...O(n/2^logn)

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

n+n/2+n/4+...+n*2^logn = n*(1+1/2+1/4+..2^logn) = n*(1-1/2+1/2-1/4 +....+ n/2^logn-1 - 1/2^logn)=n*(1 - 1/2^logn)= O(n)。所以最好情况下,时间复杂度是O(n)。

0624f7760c61ce3366cb06c43d0ca74c.png

猿六凯

最坏情况下,每次只能将范围缩小1,所以时间复杂度是:O(n + n-1 + n-2 + ... + 1) =O( (n+1)/2*n) = O(n^2)。 

0624f7760c61ce3366cb06c43d0ca74c.png d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

恩,还不错,那还有没有其他方法。

猿六凯

暂时想不到了

0624f7760c61ce3366cb06c43d0ca74c.png d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

恩,今天先到这,等下一轮面试吧。

猿六凯

恩恩,谢谢黑脸面试官。

0624f7760c61ce3366cb06c43d0ca74c.png d06958c70bead28ea9e622ad9c03c5d2.png

黑脸面试官

你说谁脸黑,你没下一次面试了。

    欢迎订阅,每周更新面试高频算法题。从思路,代码,时间复杂度等多方面进行分析。

c38102ab9c4d0dcfcb9d34ba79b317b6.png
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值