TopK算法——基于小顶堆分析

5 篇文章 0 订阅

215. 数组中的第K个最大元素

难度:中等

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2 输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

力扣:

https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

解题思路:

基于小顶堆思路,先用K个数字建立小顶堆,

然后遍历数组,对比数组当前值与小顶堆堆顶元素的值,

若大于,替换堆顶元素,调整堆结构。

代码:

package com.ziling.goodlife.study;

/**
 * @Author: yipeng
 * @Date: 2021/6/21 20:28
 */
public class TopK {

    /**
     * 最小堆的结构调整
     * @param arr   数组
     * @param index   结束位置
     */
    private static void adjustHeap(int[] arr, int index) {
        // 获取父节点坐标
        for (int i = index / 2; i > 0; i--) {
            // 记录父节点值(遍历过程中,第一次执行到此处时,记录父节点的值,相当于一个temp,只用于记录值。该值最终会替换掉遍历过程中最小的那个值)
            int parentVal = arr[i];
            // 记录父节点下标(该下标值,会在下面遍历中位置下推)
            int parentIndex = i;
            // 不超过index节点情况下,遍历该父节点下子节点情况。
            while (parentIndex * 2 <= index) {
                // 获取当前父节点的左节点
                int childIndex = parentIndex * 2;
                // 判断两个儿子节点的大小,获取较小的一个儿子节点(循环遍历较小的一个,最小的最后会被替换掉)
                if (childIndex != index && arr[childIndex] > arr[childIndex + 1]) {
                    childIndex++;
                }
                // 较小子节点比父节点的值(相当于temp)大,说明该次遍历完成
                if (parentVal < arr[childIndex]) {
                    break;
                } else {
                    // 子节点较小的值放到当前父节点下标位置
                    arr[parentIndex] = arr[childIndex];
                }
                // 当前父节点下标位置下推到之前较小子节点下标位置(此处完成父节点的下标位置下推)
                parentIndex = childIndex;
            }
            // 将父节点的值(相当于temp)替换到父节点当前下标位置
            arr[parentIndex] = parentVal;
        }
    }

    private static void print(int[] nums, int start) {
        for (int i = start; i < nums.length; i++) {
            System.out.print(nums[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] nums = {34,23,6435,4234,2523,425235,234234,6345,23,54,43,23,23,43,53,2,423,6345,432,24,25,2,234,53,6546,5345,2342,63534,234,4364};
        int k = 10;
        int[] arr = new int[k + 1];
        arr[0] = Integer.MAX_VALUE;
        print(nums, 0);
        System.arraycopy(nums, 0, arr, 1, k);
        print(arr, 1);
        // 建立小顶堆
        adjustHeap(arr, k);
        print(arr, 1);
        for (int i = k; i < nums.length; i++) {
            //
            if (nums[i] > arr[1]) {
                arr[1] = nums[i];
                adjustHeap(arr, k);
            }
        }
        print(arr, 1);
    }

}

结论:

时间复杂度:O(k+nlog(k))

空间复杂度为:O( 1 )

 

参考快排:https://blog.csdn.net/longziling/article/details/118077299

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在C++中,priority_queue是一个容器适配器,用于实现优先级队列。默认情况下,priority_queue是一个大顶堆,也就是说,优先级最高的元素会被放在队列的前面。但是,我们也可以通过自定义排序规则来创建小顶堆。 在C++中,可以通过指定第三个模板参数Compare来自定义排序规则。比如,可以使用std::greater<T>来创建小顶堆,其中T是存储在priority_queue中的元素类型。例如,可以这样定义一个小顶堆的priority_queue: ```cpp std::priority_queue<int, std::vector<int>, std::greater<int>> pq; ``` 这样定义的priority_queue会根据元素的值从小到大进行排序,优先级最高的元素会被放在队列的前面。 另外,priority_queue还提供了一些成员函数来操作队列,比如empty()、size()、top()、push()、pop()等。你可以使用这些成员函数来判断队列是否为空、获取队列的大小、访问队列的第一个元素、向队列中插入元素以及移除队列中的元素。 总结起来,如果你想创建一个小顶堆的priority_queue,可以通过指定std::greater<T>作为第三个模板参数来实现。然后,你可以使用priority_queue提供的成员函数来操作队列。 #### 引用[.reference_title] - *1* [C++ STL——Queue容器、priority_queue](https://blog.csdn.net/LiuXF93/article/details/121119026)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [c++priority_queue详解](https://blog.csdn.net/qq_43679351/article/details/124825229)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

益朋

看官老爷们的打赏是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值