算法概论week2 | Leetcode 215. Kth Largest Element in an Array

这周讲到分治算法,因此我想用随机分治算法解决这道选择问题。


目录:

  • 问题描述
  • 解题步骤
  • 代码
  • 更新

问题描述

第k大的数

输入: 一列数的集合nums;一个整数k
输出: 集合S中第k大的元素


解题步骤

这道题与书上2.4节的问题如出一辙,因此,我们可以首先随机选择一个数v,然后把集合nums中的数分为三组:比v小的数,与v相等的数以及比v大的数,并分别记这三组数为left,mid,right(由于题目已经令k合法,即 1≤k≤nums.size(),我们可以不对k的合法性进行检验):

int v = nums[0];
        
for(int i = 0; i < nums.size(); i++) {
	if(nums[i] < v) left.push_back(nums[i]);
	else if(nums[i] == v) mid.push_back(nums[i]);
	else right.push_back(nums[i]);
}

如果right.size() ≥ k,则在right中继续寻找第k大的数;如果right.size() + mid.size() ≥ k,则v就是第k大的数,返回v;否则,在left中寻找第(k - right.size() - mid.size())大的数:

if(right.size() >= k) return findKthLargest(right, k);
else if(right.size() + mid.size() >= k) return v;
return findKthLargest(left, k - right.size() - mid.size());

该算法的运行时间在 O ( n ) O(n) Θ ( n ) \Theta(n) 的范围内,且其平均运行时间与最佳情形下的运行时间很接近,即: T ( n ) = T ( n / 2 ) + O ( n ) T(n) = T(n / 2) + O(n)

写到这里应该差不多了,我们提交试试:

超内存

哎?怎么超内存了?用自定义测试执行代码可以得到正确答案,说明算法基本正确,仔细看看这个用例,它很大,而且是按降序排好序了的,它要求找到最大的数,也就是说,left.size()将会很大,而mid中只有一个数,right.size()则为0。

为了使这个样例通过测试,我们可以试试换个v值,比如取v = nums[nums.size() / 2],再次提交,总算通过了~

以下是完整代码。


代码

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        vector<int> left;
        vector<int> mid;
        vector<int> right;
        
        int v = nums[nums.size() / 2];
        
        for(int i = 0; i < nums.size(); i++) {
            if(nums[i] < v) left.push_back(nums[i]);
            else if(nums[i] == v) mid.push_back(nums[i]);
            else right.push_back(nums[i]);
        }
        
        if(right.size() >= k) return findKthLargest(right, k);
        else if(right.size() + mid.size() >= k) return v;
        return findKthLargest(left, k - right.size() - mid.size());
    }
};

更新

为了避免一碰到特殊数组,算法复杂度就爆炸的问题,我们可以把v变成真正的随机数,即使用rand(),虽然运行时间在这道题上并没有得到很大的改进。

srand(time(NULL));
int index = rand() % (nums.size());
int v = nums[index];

猜你喜欢

转载自blog.csdn.net/cat_xing/article/details/82718510
今日推荐