LintCode笔记(12)——第k大元素

来源:互联网 发布:知乎关于六小龄童 编辑:程序博客网 时间:2024/04/30 04:52

在数组中找到第k大的元素

 注意事项

你可以交换数组中的元素的位置

样例

给出数组 [9,3,2,4,8],第三大的元素是 4

给出数组 [1,2,3,4,5],第一大的元素是 5,第二大的元素是 4,第三大的元素是 3,以此类推

挑战 

要求时间复杂度为O(n),空间复杂度为O(1)

这道题需要利用快速排序的思想,首先复习一下什么是快速排序。

快速排序算法的主要思想为以下几步:

(1)首先选中一个基准数;

(2)在数组中进行排序,使得比基准数小的全在他左边,比基准数大的全在他右边;

(3)对上面得到的左右区间分别执行(2)中操作,直到最终区间的数字只有一个为止。

下面对快速排序算法进行详细的解释:有如下所示的数组01234563251803

假定我们选择数组的第0个元素作为基准数X且按从小到大的顺序进行排序,有初始时i = 0 ,j = 6,X = nums[i]

首先判断nums[j] >= X吗,如果成立,则不动他同时有j--寻找下一个,如果不成立,则nums[i] = nums[j];同时i++

然后判断nums[i] < X吗,如果成立,则不动他,同时有i++寻找下一个,如果不成立,则nums[j] = nums[i];同时j--

这样操作直到i>=j为止,此时数组中比X小的在他左边,比他大的在他右边。

然后分别对得到的左右区间如此操作,直到最后区间的大小为1为止。

这个博客对快速排序讲得很详细

具体的快速排序的代码如下所示(从小到大排序):

int quickSort(vector<int> &numList, int left, int right){if (left < right)//判断left到right的这个区间是否已经排序完成{//对left到right的这个区间进行排序int i = left;int j = right;int tmp = numList[left];while (i < j)//当i>=j时,排序完成{while (i < j && tmp <= numList[j])//从数组末尾开始找,直到找到比基准数tmp小的数{j--;}if (i < j)//判断前面的循环跳出是因为没有找到还是找到了比tmp小的数{numList[i++] = numList[j];//若找到了}while (i<j && tmp > numList[i])//从数组开头开始找,直到找到比基准数tmp大的数{i++;}if (i < j)//判断前面的循环跳出是因为没有找到还是找到了比tmp大的数{numList[j--] = numList[i];//若找到了}}numList[i] = tmp;quickSort(numList, left, i - 1);quickSort(numList, i + 1, right);}}


说完了快速排序,那么如何解决这道题呢

对数组利用快速排序从大到小排序的思想,找到每一次快速排序时基准数的下标(基准数的下标即为排序好后该数的真实下标),直到找到下标为k-1的数为止。(具体怎么算时间复杂度我也不太清楚,还要学习,网上说这种算法的时间复杂度为O(n))

具体代码如下:

int quickSort(vector<int> &numList, int left, int right){//对left到right的这个区间进行排序int i = left;int j = right;int tmp = numList[left];while (i < j)//当i>=j时,排序完成{while (i < j && tmp >= numList[j])//注意与前面不一样{j--;}if (i < j){numList[i++] = numList[j];}while (i<j && tmp < numList[i])//注意与前面不同{i++;}if (i < j){numList[j--] = numList[i];}}numList[i] = tmp;return i;//返回基准数下标}int kthLargestElement(int k, vector<int> nums) {// write your code hereif (nums.size() == 0)return 0;int left = 0;int right = nums.size() - 1;while (1){int pos = quickSort(nums, left, right);if (pos == k - 1)//若找到的基准数下标为k-1,即为结果{return nums[k - 1];}if (pos > k - 1)//若找到的基准数下标比k-1大,则从其左区间中继续寻找,丢弃其右区间{right = pos - 1;}if (pos < k - 1)//若找到的基准数下标比k-1小,则从其右区间中继续寻找,丢弃其左区间{left = pos + 1;}}}



0 0
原创粉丝点击