快排的空间复杂度_手撕面试官:快排应用三颜色分类

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

4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

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

4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

我们使用整数 0、1 和 2 分别表示红色、白色和蓝色。给定一个包含红色、白色和蓝色,一共 n 个元素的数组,对它们进行交换,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

比如输入: 2 0 2 1 1 0,输出: 0 0 1 1 2 2

猿六凯

这个很简单呀。左边部分都是0,中间部分都是1,右边部分都是2。结果是个升序数组。我们可以把数组按升序排序,这样就可以了。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

排序的时间复杂度是多少?

猿六凯

像快排,归并排序这样的算法,最优时间复杂度是O(nlogn)。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

有没有更优的解法?

猿六凯

嗯,我想想。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png

猿六凯

我想到了,我们遍历一遍数组,把红色,白色,蓝色的数量分被统计下,然后在原数组里依次放入相应个数的0,1,2就可以了。这样时间复杂度是O(n),空间复杂度是O(1)。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

不错,方法可行,还给出了时间复杂度和空间复杂度。你这解法扫描了数组几趟?

猿六凯

统计个数一趟,按顺序放入一趟,一共两趟。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

有没有扫描一趟的方法?

猿六凯

我想想。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png

猿六凯

嗯,,,,这个问题有点难,没想到。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

给你提示一下。

4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

我们的目的是把原来数组分成三部分:左边部分是0,中间部分是1,右边部分是2。我们可以看出,左边部分元素都小于中间部分元素,右边部分元素都大于中间部分元素。

猿六凯

左边部分小于中间部分,右边部分大于中间部分,咋听着和快排有点像。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

方向是对的,你再想想怎么做。

猿六凯

快排的时候,我们选一个基准,把小于基准的放在左边,大于基准的放在右边。对于这个题目,我们选1为基准。0小于1,放左边;2大于1放右边。这样一趟快排就可以了。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png

猿六凯

具体的,我们用i记录排好的0的最后一个位置,用j记录排好的2的第一个位置。用k记录中间未排的元素第一个位置,如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png bfe34210c3bef0086299867110a82892.png

猿六凯

我们判断k所指向的元素与1的关系。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png

猿六凯

大于1就和未排序的最后一个位置交换,也就是j的前一个位置,如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 8618c817fa2eddda4b850f9225d54318.png

猿六凯

小于1就和第一个位置1交换,也就是i的后一个位置,如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png f770858a1c0454bd99fb1b77c81332bb.png

猿六凯

当k和j相遇就停止,如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 9fcec3d4a47ecc08570984adef469837.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

嗯,总体思路没问题。有这么一个细节,你考虑了吗?

4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

比如k指向的元素大于1,j的前一个位置的元素是0。这样交换后,是不是要做其他处理?如下图。

efbcc24a30bb3f85321ab1190ceff50e.png

猿六凯

我想想。交换后,结果如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png dda9c2068ea08239fac486710141454b.png

猿六凯

如果交换回来了0,我们这个不能直接让k+1,需要将0和i后面一个位置的数交换,如下图。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 50e82f2c40706f77ee5aa3e5f020824b.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

嗯,不错,写下代码吧。

#include using namespace std;class Solution {public:    void qiuckSort(vector<int>& a, int l, int r) {        if (l >= r) return;        //快排模板        int k = l;        int i = l - 1, j = r + 1;        while (k < j) {            if (a[k] < 1) swap(a[k], a[++i]);//如果a[k]是0,和i后面一个位置元素交换,并且i+1。            if (a[k] > 1) swap(a[k--], a[--j]);//如果a[k]是2,和j前面一个位置元素交换。并且k-1,抵消后面的k++,来再次对该位置进行判断(可能交换回来个0)。            k++;        }    }    void sortColors(vector<int>& nums) {        qiuckSort(nums, 0, nums.size() - 1);    }};int main() {    int n;//数组元素个数    cin >> n;    int num;    vector<int> nums;    while (n--) cin >> num, nums.push_back(num);    Solution s;    s.sortColors(nums);    for (auto num : nums) {        cout << num <<" ";    }}
4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

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

猿六凯

一趟快排,只扫描了一趟数组,时间复杂度是O(n),空间上交换元素需要一个额外空间,空间复杂度是O(1)。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

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

猿六凯

恩恩,谢谢黑脸面试官。

bb32b8e36a72907f1ec2b8ab2d4e63c6.png 4cb431335f61b64be29475c02af15c6c.png

黑脸面试官

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

对应leetcode题目:75. 颜色分类

此思路解题详情:

706a8a34a1b9dd2f0c49f01495b93ab7.png

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值