我实现了一种算法,该算法解决了在未排序的数组中找到 k th 个最小元素的问题。我使用了堆结构,并依靠此公式优化了代码
k 1 = n-k + 1
k 1 是 k 1 th 最大元素,所以我选择 k 和 k 1 中较小的一个。
不过,我无法通过在线裁判传递时限错误。我不知道是否还要创建一个不超过 k 大小的数组,这会带来更好的复杂性。可能少于 k 个?或者,除了使用堆结构之外,还有另一种解决此问题的方法。
1 <= k <= n <= 10 5
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
void minHeapify(int arr[], int n, int i)
{
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
if (l < n && arr[l] < arr[largest])
largest = l;
if (r < n && arr[r] < arr[largest])
largest = r;
if (largest != i) {
swap(arr[i], arr[largest]);
minHeapify(arr, n, largest);
}
}
void maxHeapify(int arr[], int n, int i)
{
int smallest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
if (l < n && arr[l] > arr[smallest])
smallest = l;
if (r < n && arr[r] > arr[smallest])
smallest = r;
if (smallest != i) {
swap(arr[i], arr[smallest]);
maxHeapify(arr, n, smallest);
}
}
void buildMinHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
minHeapify(a, n, i);
}
void buildMaxHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
maxHeapify(a, n, i);
}
int kthsmallest(int minHeap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> minHeap[i];
buildMaxHeap(minHeap, k);
for (i = k; i < n; i++)
{
cin >> temp;
if (temp < minHeap[0])
{
minHeap[0] = temp;
maxHeapify(minHeap, k, 0);
}
}
return minHeap[0];
}
int kthlargest(int minHeap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> minHeap[i];
buildMinHeap(minHeap, k);
for (i = k; i < n; i++)
{
cin >> temp;
if (temp > minHeap[0])
{
minHeap[0] = temp;
minHeapify(minHeap, k, 0);
}
}
return minHeap[0];
}
int main() {//kth smallest element
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k, k1;
cin >> n >> k;
k1 = n - k + 1;//kth smallest element is the same as k1th largest element
if (k < k1) {
int *minHeap = new int[k];
cout << kthsmallest(minHeap, k, n);
}
else {
int *minHeap = new int[k1];
cout << kthlargest(minHeap, k1, n);
}
return 0;
}
请帮助您找到更好的时间复杂度吗?
查找数组的第k个第个最大元素
内存限制: 256 MB
时间限制: 1 s
输入:input.txt
输出: output.txt
任务:
您会得到一个由 n 个整数组成的数组和一个自然的 k 。
您必须找到数组的 k th 个最大元素。
您创建的数组不能超过 k 个元素。输入:
第一行包含自然的 n (1≤ n ≤10 5 )– 数组元素的数量以及自然的 k 。
第二行包含 n 个数字-数组的元素。输出:
数组中第 k th 个最大元素。
示例:
Input | Output -------------+----------- 6 2 | 7 7 4 6 3 9 1 |
答案 0 :(得分:1)
时间复杂度是最佳的,但是您可以使代码效率更高一点:
swap
,而是将原始值保留在内存中,同时将子值复制到其父项,并且仅在到达适当的插槽后才存储初始值。2 * i
:另一个子节点只是下一个。i
上的当前值,也可以是它的替换值。这样可以节省一项任务。这是查找两个heapify函数的方式:
void minHeapify(int arr[], int n, int i, int key) { // add key as parameter
while (true) { // iterative
int child = 2 * i + 1; // do this only for left child, and limit number of variables
if (child+1 < n && arr[child] > arr[child+1]) // get child with least value
child++; // the right child is just one index further
if (child >= n || key <= arr[child]) break;
arr[i] = arr[child]; // don't swap, just copy child value to parent
i = child; // move down
}
arr[i] = key; // finally put the original value in the correct place
}
void maxHeapify(int arr[], int n, int i, int key) { // add key as parameter
while (true) { // iterative
int child = 2 * i + 1; // do this only for left child, and limit number of variables
if (child+1 < n && arr[child] < arr[child+1]) // get child with greatest value
child++; // the right child is just one index further
if (child >= n || key >= arr[child]) break;
arr[i] = arr[child]; // don't swap, just copy child value to parent
i = child; // move down
}
arr[i] = key; // finally put the original value in the correct place
}
void buildMinHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
minHeapify(a, n, i, a[i]); // pass a[i] also
}
void buildMaxHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
maxHeapify(a, n, i, a[i]); // pass a[i] also
}
int kthsmallest(int heap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> heap[i];
buildMaxHeap(heap, k);
for (i = k; i < n; i++) {
cin >> temp;
if (temp < heap[0])
maxHeapify(heap, k, 0, temp); // pass temp
}
return heap[0];
}
int kthlargest(int heap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> heap[i];
buildMinHeap(heap, k);
for (i = k; i < n; i++) {
cin >> temp;
if (temp > heap[0])
minHeapify(heap, k, 0, temp); // pass temp
}
return heap[0];
}
在主函数中,您可以对 k == 1 或 k == n 进行特殊处理,因此不需要堆,只需min()
或max()
。
一件奇怪的事是,您链接到的挑战说的是“最大 k > 最小”。也许你混了。
这是工作返回最小的 k th 时的代码。但是请检查挑战,是否不应该对最大的 k th 做到这一点?
int main() {//kth smallest element
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k, k1;
cin >> n >> k;
k1 = n - k + 1;//kth smallest element is the same as k1th largest element
if (k == 1) {
int curr, next;
cin >> curr;
for (int i = 1; i < n; i++) {
cin >> next;
curr = min(curr, next);
}
cout << curr;
} else if (k1 == 1) {
int curr, next;
cin >> curr;
for (int i = 1; i < n; i++) {
cin >> next;
curr = max(curr, next);
}
cout << curr;
} else if (k < k1) {
int *heap = new int[k];
cout << kthsmallest(heap, k, n);
} else {
int *heap = new int[k1];
cout << kthlargest(heap, k1, n);
}
return 0;
}
答案 1 :(得分:0)
您假设使用较小的堆始终是最佳选择。您可能需要重新考虑。
例如,假设您想从100的列表中选择第96个最小的数字。如果您使用大小为96的堆,那么您将这样做:
buildHeap
为O(n),在这种情况下,n
为96。如果使用大小为4的堆,则将执行以下操作:
第一个选项是96 + 4 * log(96)。 96的以2为底的对数约为6.58。因此插入的费用为26.32,总计122.32。
堆较小的第二个选项是4 + 96 * log(4)。 log(4)是2,所以最终得到4 + 196,或总共196。
较小的堆是这里的大输家。
通常,您想在(k + (n-k)*log(k)) < ((n-k) + k*log(n-k))
时使用更大的堆。
也:
堆选择算法的实际运行时间对项目的显示顺序很敏感。例如,如果您正在寻找100,000个数组中的第1000个最小数字,那么如果数组按升序排列,则其运行速度将比按降序排列的速度快得多。原因?
因为在递增的情况下,您使用前1,000个项构建了初始堆,因此您无需再修改堆,因为以下项都不比堆中的最大项小。
但是,如果数组是降序排列的,那么您查看的每个项目都将小于堆中最大的项目,这意味着您将为所有99,000个剩余项目进行堆插入。
想象一下,如果其中一个测试用例是一个降序的大数组,那么代码的性能如何。
除非您已经证明选择使用哪种堆大小的方法明显更好,否则您可能要考虑使用大小为k的最大堆来选择“选择第k个最小”。