C++ 经典算法题目前k大的数

求一个给定数组的前k个数有多种方法一

方法一:排序取前k个数,时间复杂度nlogn

方法二:维护一个最大堆,时间复杂度nlogn

方法三:维护一个容量为k的最小堆,代码如下,时间复杂度O(nlogk)

#include <iostream>
#include <vector>
#include <queue>

std::vector<int> findKthLargest(std::vector<int>& nums, int k)
{
	// 维护一个k个元素的最小堆
	// 先将前k个元素优先队列,遍历真个数组,如果数组比最小值大,弹出堆顶元素,入队列
	// 时间复杂度 nlogk 
	std::vector<int> res;
	std::priority_queue<int, std::vector<int>, std::greater<int> > pq(nums.begin(), nums.begin() + k);
	for (int i = k; i < nums.size(); i++) {
		if (nums[i] > pq.top()) {
			pq.pop();
			pq.push(nums[i]);
		}
	}
	while (!pq.empty()) {
		res.push_back(pq.top());
		pq.pop();
	}
	return res;
	
}

int main() 
{
	std::vector<int> arr;
	std::vector<int> res;
	int n, k, temp;
	std::cin >> n;
	for (int i = 0; i < n; i++) {
		std::cin >> temp;
		arr.push_back(temp);
	}
	std::cin >> k;
	res = findKthLargest(arr, k);
	//std::cout << res.size();
	for (int i = res.size() - 1; i >= 0; i--)
		std::cout << res[i] << std::endl;
}

方法四:使用快排的操作加分治解决。

快排的第一步操作,使得存在一个标志位key,左边的数都小于这个数,右边的数都大于这个数,再次建立一个递归函数,使得右边的数字个数恰好是k即可

简单快排代码

void QuickSort(int arr[], int start, int end) {
	if (start >= end)
		return;
	int k = arr[start];
	int i = start, j = end;
	while (i != j) {
		while (j > i && arr[j] >= k)
			j--;
		std::swap(arr[i], arr[j]);
		while (i < j&&arr[i] <= k)
			i++;
		std::swap(arr[i], arr[j]);
	}
	QuickSort(arr, start, i - 1);
	QuickSort(arr, i + 1, end);
}

arrangeRight函数使得数组分成两半,标志位左边的数都小于它,标志位右边的数都大于它

如果右边的数的个数恰好等于k,那么直接返回

如果右边的数的个数小于k,这个数即为n,那么要往左边移动n-k个数过来

如果右边的数的个数大于k,递归到右边第i+1的位置。

void arrangeRight(int arr[], int m, int start, int end) {
	int k = arr[start];
	int i = start, j = end;
	while (i != j) {
		while (j > i && arr[j] >= k)
			j--;
		std::swap(arr[i], arr[j]);
		while (i < j&&arr[i] <= k)
			i++;
		std::swap(arr[i], arr[j]);
	}
	if (end - i + 1 == m)
		return;
	else if (end - i + 1 > m)
		arrangeRight(arr, m, i + 1, end);
	else
		arrangeRight(arr, m-end+i-1, start, i-1);
}

完整代码

#include <iostream>
#include <vector>
#include <queue>
#define N 100000

void QuickSort(int arr[], int start, int end) {
	if (start >= end)
		return;
	int k = arr[start];
	int i = start, j = end;
	while (i != j) {
		while (j > i && arr[j] >= k)
			j--;
		std::swap(arr[i], arr[j]);
		while (i < j&&arr[i] <= k)
			i++;
		std::swap(arr[i], arr[j]);
	}
	QuickSort(arr, start, i - 1);
	QuickSort(arr, i + 1, end);
}

void arrangeRight(int arr[], int m, int start, int end) {
	int k = arr[start];
	int i = start, j = end;
	while (i != j) {
		while (j > i && arr[j] >= k)
			j--;
		std::swap(arr[i], arr[j]);
		while (i < j&&arr[i] <= k)
			i++;
		std::swap(arr[i], arr[j]);
	}
	if (end - i + 1 == m)
		return;
	else if (end - i + 1 > m)
		arrangeRight(arr, m, i + 1, end);
	else
		arrangeRight(arr, m-end+i-1, start, i-1);
}

int main() 
{
	int arr[N];
	int n, k;
	std::cin >> n;
	for (int i = 0; i < n; i++)
		std::cin >> arr[i];
	std::cin >> k;
	arrangeRight(arr, k, 0, n - 1);
	QuickSort(arr, n - 1 - k - 1, n - 1);
	for (int i = n - 1; i >= n - k; i--)
		std::cout << arr[i] << std::endl;
}

 

点赞