分治算法求解kth largest element问题

来源:互联网 发布:阿里云 香港节点 速度 编辑:程序博客网 时间:2024/06/11 05:06

Leetcode: Kth largest element in an array

1.题目描述

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,

Given [3,2,1,5,6,4] and k = 2, return 5.

2.题目分析

简单来说,题目要求我们从一堆数中选出第k大的数。对于此类问题,我们首先应该想到的是:对整个数组进行排序,然后直接返回排序后数组中第k大的数就行了(未排序的数组,或者不经过排序是不能使用此方法的)。

对于数组进行排序有很多算法,我们也可以使用头文件中的sort函数进行排序,但是这样的解法很暴力,接下来我们介绍如何通过分治策略解决这个问题。

The divide-and-conquer strategy solves a problem by:

1.Breaking it into subproblems that are themselves smaller instances of the same type of problem.

2.Recursively solving these subproblems.

3.Appropriately combining their answers.

                                  ----《算法概论》

分治策略最重要的是通过递归的思想来不断缩小子问题的规模,先解决子问题,最后原问题就迎刃而解了

要想找到第K大的数,我们的首先要找到将原问题化为规模更小的子问题的方法。也就是说,我们要把在n个数里面找到第k大的数,转化为在m(m < n)个数里面找到第t(t和n的关系尚不可知)大的数。既然我们从n里面选出了m个数,那还剩下的就是n-m个数,很容易的我们就可以联想到将原先的n个数,先分成两个小的数组,然后在进行接下来的运算。

那问题又来了,我们应该以什么标准来划分这两个数组呢?一个很简单的方法就是,先从原数组里面随机找一个数boundary,大于这个数的放进一个数组,小于这个数的放在另一个数组,这样就将问题规模减小了。

但是还有一个很关键的地方是”Appropriately combining their answers”。我们要找的是第k大的数,但是这个第k大的数在子问题中不一定就是k,他有以下几种情况(k == 4)(假设已经排序后K所处的位置与large数组长度的关系):

具体分析图待上传

需要注意的是,我们是按照数组中的数来分解问题,而不是下标(index)!

3.代码实现

首先我们要将大数组分为两个数组:

    int size = nums.size();    std::vector<int> small;    std::vector<int> large;    int bounder = rand() % size;

通过循环遍历原数组中的每一个元素,得到需要求解的子问题的数组

    for (int i = 0; i< size; i++) {            if (i != bounder) {                if (nums[i] >= nums[bounder]) {                    large.push_back(nums[i]);                } else {                    small.push_back(nums[i]);                }            }        }

得到了子问题中的数组,我们要求解的就是原问题的中k应该在哪一个子数组中的哪一个位置,具体的情况和上述讨论中一样,但是需要注意的是判断条件不能将(size < k)写在 (size + 1 == k)之前,因为条件2也是满足条件1的,所以整个判断语句根本不会进入条件2,这样就漏掉了很关键的一个返回条件。

    size = large.size();    if (size >= k) {        return findKthLargest(large, k);    } else if (size + 1 == k) {        return nums[bounder];    } else if (size < k) {        return findKthLargest(small, k - size - 1);    }

完整代码

    int findKthLargest(vector<int>& nums, int k) {        int size = nums.size();        std::vector<int> small;        std::vector<int> large;        int bounder = rand() % size;        for (int i = 0; i< size; i++) {            if (i != bounder) {                if (nums[i] >= nums[bounder]) {                    large.push_back(nums[i]);                } else {                    small.push_back(nums[i]);                }            }        }        size = large.size();        if (size >= k) {            return findKthLargest(large, k);        } else if (size + 1 == k) {            return nums[bounder];        } else if (size < k) {            return findKthLargest(small, k - size - 1);        }    }

4.体会

低于分治算法和递归理解还是不够,还需要加强练习。

有任何问题欢迎在评论区留言。

阅读全文
0 0
原创粉丝点击