快排这个东西真的不想说什么,刷面经常常看到会有面试官考察快排的代码,我一直觉得这种事情不会发生在我身上,没想到上周滴滴面试还是发生了。而且,我之前写过好几次快排的代码,然而面试时脑子一篇空白,没有按时写出来……并且像面试官问了一个巨他妈愚蠢的问题:现在的语言都有sort这种已经非常完善的排序算法,为什么还要造轮子手撕快排。面试官说:其实让你们写快排的代码并不是要你们造轮子取代那些排序算法,而是通过快排这个我们都知道原理的过程来看看你的code基本功,能不能把这个我们都知道的思路复现出来。
简单点说,写不出来就是菜鸡了。看完这篇文章,拒绝做菜鸡!
先看一道leetcode上的medium级别的题目:
215. 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
这个题有很多思路,用python刷题的同学不要sort一下直接返回nums[k-1],这样学不到东西的。
清楚快排原理的同学应该不难想到这道题可以用快排的思想,但我们又不需要将每一段都排序,只需要确定好第k-1个位置的数就行,那个数就是第k大的数。
考虑到局部有序的情况,我们在选择参照数的时候,可以用一下随机数选取参照数。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution {public : int findKthLargest (vector <int >& nums, int k) { return quickSort(nums, 0 , nums.size()-1 , k-1 ); } int quickSort (vector <int >& nums, int l, int r, int k) { int p=randomPartition(nums, l, r); if (p==k) return nums[p]; else return p<k?quickSort(nums, p+1 , r, k):quickSort(nums, l, p-1 , k); }; int randomPartition (vector <int >& nums, int l, int r) { int p=rand()%(r-l+1 )+l; swap(nums[p], nums[r]); return partition(nums, l, r); } int partition (vector <int >& nums, int l, int r) { int x=nums[r], i=l-1 ; for (int j=l; j<=r; ++j) { if (nums[j]>x) { swap(nums[++i], nums[j]); } } swap(nums[++i], nums[r]); return i; } };
由这个算法我们应该可以把快排的代码完整写出来了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> #include <vector> int partition (std ::vector <int >& arr, int l, int r) { int x=arr[r], i=l-1 ; for (int j=l; j<=r; ++j) { if (arr[j]<x) { std ::swap(arr[++i], arr[j]); } } std ::swap(arr[++i], arr[r]); return i; } void quickSort (std ::vector <int >& arr, int l, int r) { if (l>r) return ; int p=partition(arr, l, r); quickSort(arr, l, p-1 ); quickSort(arr, p+1 , r); } int main (int argc, char const *argv[]) { std ::vector <int > arr={8 ,7 ,6 ,3 ,5 ,4 ,1 ,2 ,9 ,0 }; quickSort(arr, 0 , arr.size()-1 ); for (int i:arr) { std ::cout << i << " " ; } std ::cout << std ::endl ; return 0 ; }
基本功也好,八股文也罢,快排写不出来确实尴尬。
奇技淫巧,唯手熟尔。