一道关于快排的题目

这是一道来自LintCode的题目,题目原文是这样的:

LeetCode对应的题号是215。

我的做法:

class Solution {
public:
    /**
     * @param n: An integer
     * @param nums: An array
     * @return: the Kth largest element
     */
    int kthLargestElement(int n, vector<int> &nums) {
        int tmp=0;
        tmp = partition(nums, 0, nums.size()-1, nums.size() - n);
        for (int i = nums.size()-1; i >= 0; i--){
            cout << nums[i] << endl;
        }
        return tmp;
    }
private:
    int partition(vector<int> &nums, int start, int end, int k) {
        // 一定要有这个,不然就一直递归下去了
        if (start >= end) {
            return nums[k];
        }
        
        int left = start;
        int right = end;
        int pivot = nums[(start + end) / 2];
        while(left<=right){
            while (nums[left]<pivot && left <= right)left++;
            while (nums[right]>pivot && left <= right)right--;
            if(left<=right){
                // 其实用C++自带的swap也行,但是运行速度会慢一点
                swap(nums, left, right);
                left++;
                right--;
            }
        }
        
        partition(nums, start, right, k);
        partition(nums, left, end, k);
        return nums[k];
    }    
    
    void swap(vector<int> &nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
};

其实核心思想就是快排,这里粗略讲一下思路:

  1. 选取基准数字

其实选取基准数字的方法不固定,我这里是选择了数组中间的数字作为基准(省事一点)。

  1. 开始比较

例子来自坐在马桶上看算法:快速排序,此处略有改动。例如数组是6 1 2 7 9 3 4 5 10 8
我们从两端开始探测:

那两个小人就是当前在操作的数字,首先左边的小人会向右走,同时将自己脚下面的数字和基准数字进行比较,因为我们排列的目的是让数字升序排列,即最终结果为1 2 3 ... 10,所以左侧小人探测的目标是比基准数字大的数字。左侧小人找到目标并停下后,右侧小人会开始向左走,探测目标是比基准数字小的数字。两个小人都是一旦发现了目标就在目标上方停下。两个小人都找到自己对应的目标之后就会进行交换。

如此类推,直到两个小人碰在了一起:

这时候就应该将数组分割成两部分,然后在每个部分中单独重复上述步骤。


注意我的程序中的判断条件,我的目的是在碰面之后再让左右的“小人”继续走一步,然后直接依据两个小人的位置将数组进行分割。

posted @ 2019-07-02 16:20  夜溅樱  阅读(296)  评论(0编辑  收藏  举报