18、数组中的第K个最大元素
题目
18.0、暴力解法
直接sort排序
int findKthLargest0(vector<int>& nums, int k)
{
sort(nums.begin(), nums.end());
return nums[nums.size() - k];
}
- 时间复杂度:O(n平方)
- 空间复杂度:O(1)
18.1、基于快速排序的选择方法
利用sort排序的原理,进行快速选择,对于数组【3,2,3,1,2,4,5,5,6】
-
随机选择一个下标比如2,遍历一遍数组将大于等于3的都移动到2的左边,小于3的都移动到2的右边
-
得到【5,4,5,3,6,3,1,2,2】(结果可能顺序并不是这样,只是为了说明分成两部分后仍是乱序)
-
如果需要的是第6大的数,那就可以直接返回3了
-
如果需要第4(在分界点前面)大的数,那就对序列【5,4,5,3,6】重复上述步骤
-
如果需要第7(在分界点后面)大的数,那就对序列【1,2,2】重复上述步骤
最后的***最高速度***完全靠运气。。。
private:
//随机一个下标,然后将该数与最后一个数调换
int randomPartition(vector<int>& nums, int leftIndex, int rightIndex)
{
srand((unsigned int)time(0));
int randNum = rand() % (rightIndex - leftIndex + 1) + leftIndex;
swap(nums[randNum], nums[rightIndex]);
return partition(nums, leftIndex, rightIndex);
}
//根据最后一个数,将数组分为两部分,前一部分比最后一个数大,后一部分比最后一个数小
int partition(vector<int>& nums, int leftIndex, int rightIndex)
{
int flagIndex = leftIndex; //左右的分界线
for (int i = leftIndex; i < rightIndex; i++)
if (nums[i] >= nums[rightIndex])
{
swap(nums[flagIndex], nums[i]);
flagIndex++;
}
swap(nums[flagIndex], nums[rightIndex]);
return flagIndex; //返回分界线坐标
}
//快速选择
int quickSelect(vector<int>& nums, int leftIndex, int rightIndex, int k)
{
int flagIndex = randomPartition(nums, leftIndex, rightIndex);
if (flagIndex == k)
return nums[flagIndex];
else
return flagIndex < k ? quickSelect(nums, flagIndex + 1, rightIndex, k) : quickSelect(nums, leftIndex, flagIndex - 1, k);
}
public:
//基于快速排序的选择方法
int findKthLargest1(vector<int>& nums, int k)
{
return quickSelect(nums, 0, nums.size() - 1, k - 1);
}
- 时间复杂度:O(n)证明参见算法导论
- 空间复杂度:O(log n)递归占用的空间
18.2、基于堆排序的选择方法
emmmm,还是去看书吧(~_~!)
- 时间复杂度:O(n log n)
- 空间复杂度:O(log n)