TopK问题

问题描述

对于给定无序序列,返回第K大的元素。

215. Kth Largest Element in an Array

解法汇总

解法一:快排法

利用快速排序的partition算法求解TopK问题,这种解法充分利用了partition算法的优越性,假设序列不是有序或近似有序的,每轮划分后,下一轮只需要求解一半的序列,大大降低了时间复杂度。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return findTopK(nums, 0, nums.size()-1, k, k);
    }
    
    int findTopK(vector<int>& nums, int p, int r, int k, int originK) {
        if(p < r && k > 0) {
            int q = partition(nums, p, r);
            int biggerSize = nums.size() - q - 1;
            if(biggerSize >= originK) { // 比基准大的子序列长度大于K个
                findTopK(nums, q+1, r, k, originK); // 从右边找k个
            } else {
                findTopK(nums, p, q-1, originK-biggerSize, originK); // 从左边找
            }
        } 
        return nums[nums.size()-originK]; // 最大的k个元素已经有序,直接返回
    }
    
    // 以基准元素对序列进行partition
    int partition(vector<int>& nums, int p, int r) {
        int x = nums[r], i = p-1;
        for(int j = p; j < r; j++) {
            if(nums[j] <= x) {
                i++;
                swap(nums, i, j);
            }
        }
        swap(nums, i+1, r);
        return i+1;
    }
    
    void swap(vector<int>& nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
};

解法分数:Runtime: 60 ms, faster than 17.91% of C++ online submissions for Kth Largest Element in an Array.

需求响应动态冰蓄冷系统与需求响应策略的优化研究(Matlab代码实现)内容概要:本文围绕“需求响应动态冰蓄冷系统与需求响应策略的优化研究”展开,基于Matlab代码实现,重点探讨了冰蓄冷系统在电力需求响应背景下的动态建模与优化调度策略。研究结合实际电力负荷与电价信号,构建系统能耗模型,利用优化算法对冰蓄冷系统的运行策略进行求解,旨在降低用电成本、平衡电网负荷,并提升能源利用效率。文中还提及该研究为博士论文复现,涉及系统建模、优化算法应用与仿真验证等关键技术环节,配套提供了完整的Matlab代码资源。; 适合人群:具备一定电力系统、能源管理或优化算法基础,从事科研或工程应用的研究生、高校教师及企业研发人员,尤其适合开展需求响应、综合能源系统优化等相关课题研究的人员。; 使用场景及目标:①复现博士论文中的冰蓄冷系统需求响应优化模型;②学习Matlab在能源系统建模与优化中的具体实现方法;③掌握需求响应策略的设计思路与仿真验证流程,服务于科研项目、论文写作或实际工程方案设计。; 阅读建议:建议结合提供的Matlab代码逐模块分析,重点关注系统建模逻辑与优化算法的实现细节,按文档目录顺序系统学习,并尝试调整参数进行仿真对比,以深入理解不同需求响应策略的效果差异。
综合能源系统零碳优化调度研究(Matlab代码实现)内容概要:本文围绕“综合能源系统零碳优化调度研究”,提供了基于Matlab代码实现的完整解决方案,重点探讨了在高比例可再生能源接入背景下,如何通过优化调度实现零碳排放目标。文中涉及多种先进优化算法(如改进遗传算法、粒子群优化、ADMM等)在综合能源系统中的应用,涵盖风光场景生成、储能配置、需求响应、微电网协同调度等多个关键技术环节,并结合具体案例(如压缩空气储能、光热电站、P2G技术等)进行建模与仿真分析,展示了从问题建模、算法设计到结果验证的全流程实现过程。; 适合人群:具备一定电力系统、能源系统或优化理论基础,熟悉Matlab/Simulink编程,从事新能源、智能电网、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①开展综合能源系统低碳/零碳调度的科研建模与算法开发;②复现高水平期刊(如SCI/EI)论文中的优化模型与仿真结果;③学习如何将智能优化算法(如遗传算法、灰狼优化、ADMM等)应用于实际能源系统调度问题;④掌握Matlab在能源系统仿真与优化中的典型应用方法。; 阅读建议:建议结合文中提供的Matlab代码与网盘资源,边学习理论模型边动手调试程序,重点关注不同优化算法在调度模型中的实现细节与参数设置,同时可扩展应用于自身研究课题中,提升科研效率与模型精度。
### Top k 问题的详细介绍 Top k 问题指的是求数据集合中前 k 个最大的元素或者最小的元素,一般情况下数据量都比较大。比如专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等,都属于 Top k 问题的实际应用场景[^1]。 ### Top k 问题的解决方案 #### 1. 排序法 最简单直接的方式就是对所有数据进行排序,然后取前 k 个元素。不过这种方法存在明显弊端,快速排序的平均复杂度为 $O(nlogn)$,但最坏时间复杂度为 $O(n^2)$,不能始终保证较好的复杂度。并且只需要前 k 大的元素,却对其余不需要的数也进行了排序,浪费了大量排序时间[^2]。 #### 2. 堆解法 最佳的方式是用堆来解决。基本思路是用数据集合中前 k 个元素来建堆,若求前 k 个最大的元素,则建小堆;若求前 k 个最小的元素,则建大堆。以下是使用 C 语言实现用堆解决 Top k 问题的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> // 向下调整函数 void AdjustDown(int* topk, int k, int i) { int parent = i; int child = 2 * parent + 1; while (child < k) { if (child + 1 < k && topk[child + 1] < topk[child]) { child++; } if (topk[child] < topk[parent]) { int temp = topk[child]; topk[child] = topk[parent]; topk[parent] = temp; parent = child; child = 2 * parent + 1; } else { break; } } } // 打印前 k 个最大元素 void PrintTopk(const char* file, int k) { int* topk = (int*)malloc(sizeof(int) * k); FILE* fout = fopen(file, "r"); if (fout == NULL) { perror("fopen error"); return; } // 读出前 k 个建堆 for (int i = 0; i < k; i++) { fscanf(fout, "%d", &topk[i]); } for (int i = (k - 1 - 1) / 2; i >= 0; i--) { AdjustDown(topk, k, i); } // 用剩余的 n - k 个元素依次与堆顶元素来比较,不满足则替换堆顶元素 int val = 0; int ret = fscanf(fout, "%d", &val); while (ret != EOF) { if (val > topk[0]) { topk[0] = val; AdjustDown(topk, k, 0); } ret = fscanf(fout, "%d", &val); } for (int i = 0; i < k; i++) { printf("%d ", topk[i]); } free(topk); fclose(fout); } // 测试函数 void TestTopk() { int n = 10000; srand(time(0)); const char* file = "data.txt"; FILE* fin = fopen(file, "w"); if (fin == NULL) { perror("fopen error"); return; } for (size_t i = 0; i < n; i++) { int x = rand() % 10000; fprintf(fin, "%d\n", x); } PrintTopk(file, 10); } int main() { TestTopk(); return 0; } ``` 该代码通过文件存储数据,先读取前 k 个元素构建小堆,再用剩余元素与堆顶比较,若比堆顶大则替换堆顶并调整堆,最终输出前 k 个最大元素[^4]。 #### 3. 快速选择法 快速选择可以看做是快速排序的子过程,只关注某一部分元素的选择过程。例如,寻找数组中 top - k 个最小的元素,假设某一次 partition 后 pivot 元素所在的数组索引为 m: - 若 $m == k$,那么它之前的 k 个元素即所求结果,直接返回即可; - 若 $m > k$,那么最小的 k 个元素必定位于 pivot 的左侧,只需要对左侧数组递归进行 partition; - 若 $m < k$,那么 pivot 左侧的 m 个元素是结果的一部分,还需对右侧数组递归进行 partition寻找右侧数组中最小的 $k - m$ 个元素[^3]。 #### 4. 优先队列法 在 Java 中可以使用优先队列(堆)来解决 Top k 问题。以下是一个求数组中最小的 k 个数的 Java 代码示例: ```java import java.util.PriorityQueue; import java.util.Comparator; class Solution { public int[] smallestK(int[] arr, int k) { if (arr == null || k == 0) { return new int[0]; } PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); // 然后将前 k 个数据加入 for (int i = 0; i < k; i++) { priorityQueue.offer(arr[i]); } // 从下标第 k 个开始判断,小则删除堆顶,加入 for (int i = k; i < arr.length; i++) { int val = priorityQueue.peek(); if (val > arr[i]) { // 弹出大 priorityQueue.poll(); // 加入小的 priorityQueue.offer(arr[i]); } } // 加入数组 int[] temp = new int[k]; for (int i = 0; i < k; i++) { temp[i] = priorityQueue.poll(); } return temp; } } ``` 该代码先将前 k 个数据构建成大根堆,然后从第 k 个下标开始比较堆顶数据和当前下标的数据,如果比堆顶的小,则删除堆顶数据,添加当前下标数据,然后进行调整,直到遍历完数组后,堆中的 k 个数据就是最小的 k 个数,最后将堆中数据放入数组返回[^5]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值