面试经典问题 —— 最大/小前K个数问题(top - K)问题

embedded/2024/12/27 1:01:02/

目录

  • 常见思路
  • 更优的解法(面试官喜欢的)

在这里插入图片描述

常见思路

要选出最小的前K个数首先我们会想到排排升序建大堆,排降序建小堆

一个直观的想法是使用(小根堆),起始将所有元素放入堆中,然后再从堆中取出k 个元素并「顺序」构造答案。

你写出了用小堆解决的代码


void swap(int* a, int* b) {int t = *a;*a = *b;*b = t;
}void minHeapify(int arr[], int n, int i) {int smallest = i;int left = 2 * i + 1;int right = 2 * i + 2; if (left < n && arr[left] < arr[smallest])smallest = left;if (right < n && arr[right] < arr[smallest])smallest = right;if (smallest != i) {swap(&arr[i], &arr[smallest]);minHeapify(arr, n, smallest);}
}void buildMinHeap(int arr[], int n) {// Index of last non-leaf nodeint startIdx = (n / 2) - 1;for (int i = startIdx; i >= 0; i--)minHeapify(arr, n, i);
}int extractMin(int arr[], int* n) {if (*n <= 0)return INT_MAX;if (*n == 1) {(*n)--;return arr[0];}int root = arr[0];arr[0] = arr[*n - 1];(*n)--;minHeapify(arr, *n, 0);return root;
}void findKSmallest(int arr[], int n, int k) {buildMinHeap(arr, n);printf("The k smallest elements are: ");for (int i = 0; i < k; i++) {printf("%d ", extractMin(arr, &n));}printf("\n");
}

分析一下不难发现
建堆的复杂度是 O(N)
每次提取的复杂度是 O(logN)
总的复杂度O(NlogN)

面试官看到你的代码后,并不满意并要求你进行优化

更优的解法(面试官喜欢的)

使用(大根堆)!
当处理到原始 arr[i] 时,根据堆内元素个数,以及其与堆顶元素的关系分情况讨论:
堆内元素不足 k 个:直接将 arr[i] 放入堆内;
堆内元素为 k 个:根据 arr[i] 与堆顶元素的大小关系分情况讨论:
arr[i]>=heapTop:arr[i] 不可能属于第 k 小数(已有 k 个元素在堆中),直接丢弃 arr[i];
arr[i]<heapTop:arr[i] 可能属于第 k 小数,弹出堆顶元素,并放入 arr[i]。

在这里插入图片描述

你出写了如下代码

void swap(int* a, int* b) {int t = *a;*a = *b;*b = t;
}void maxHeapify(int arr[], int n, int i) {int largest = i;int left = 2 * i + 1;int right = 2 * i + 2; // 如果左子节点大于当前节点,则更新最大值索引if (left < n && arr[left] > arr[largest])largest = left;// 如果右子节点大于当前节点,则更新最大值索引if (right < n && arr[right] > arr[largest])largest = right;// 如果最大值索引不是当前节点,则交换并递归调整子树if (largest != i) {swap(&arr[i], &arr[largest]);maxHeapify(arr, n, largest);}
}void buildMaxHeap(int arr[], int n) {// 最后一个非叶子节点的索引int startIdx = (n / 2) - 1;// 从最后一个非叶子节点开始,逆序遍历并调整每个节点for (int i = startIdx; i >= 0; i--)maxHeapify(arr, n, i);
}// 提取堆顶元素并调整堆的函数
int extractMax(int arr[], int* n) {if (*n <= 0)return INT_MAX; // 堆为空时返回最大整数值if (*n == 1) {(*n)--;return arr[0]; // 堆只有一个元素时直接返回}// 存储并移除堆顶元素int root = arr[0];arr[0] = arr[*n - 1];(*n)--;maxHeapify(arr, *n, 0); // 调整堆以保持大根堆性质return root;
}void findKSmallest(int arr[], int n, int k) {// 构建包含前k个元素的大根堆int heap[k];for (int i = 0; i < k; i++) {heap[i] = arr[i];}buildMaxHeap(heap, k);// 遍历剩余元素for (int i = k; i < n; i++) {// 如果当前元素小于堆顶元素,则替换堆顶元素并重新调整堆if (arr[i] < heap[0]) {heap[0] = arr[i];maxHeapify(heap, k, 0);}}
}

时间复杂度O(NlogK),当N无限大时logK可以忽略
比O(NlogN)更优


http://www.ppmy.cn/embedded/149043.html

相关文章

微服务学习

1、微服务的五大组件 2、eureka服务注册和发现 3、负载均衡的实现 4、服务雪崩及如何解决 5、微服务监控-skywalking 6、微服务限流

合合信息:探索视觉内容安全新前沿

2024年12月13日-15日&#xff0c;中国图象图形学学会在杭州召开。大会期间&#xff0c;来自合合信息的图像算法研发总监郭丰俊进行了主题为“视觉内容安全技术的前沿进展与应用”的演讲&#xff0c;介绍了视觉内容安全问题&#xff0c;并总结了现今的技术发展&#xff0c;对我很…

myql explain sql分析详解

Explain 命令中的 type 列&#xff0c;显示MySQL查询所使用的 关联类型&#xff08;Join Types&#xff09; 或者 访问类型&#xff0c;它表明 MySQL决定如何查找表中符合条件的行。 常见访问类型性能由最差到最优依次为&#xff1a;ALL < index < range < index_subq…

Vue3中404页面捕获(图文详情)

Vue3中404页面捕获&#xff08;图文详情&#xff09; 在 Vue 项目中&#xff0c;捕获并处理 404 页面&#xff08;即“未找到页面”或“页面不存在”&#xff09; 是非常重要的&#xff0c;尤其是在构建单页面应用程序&#xff08;SPA, Single Page Application&#xff09;时…

论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 王志豪&#xff0c;厦门大学博士生 刘诗雨&#xff0c;厦门大学硕士生 内容简介 新数据的不断涌现使版本更新成为大型语言模型&#xff08;LLMs&#xff…

2025年入职/转行网络安全,该如何规划?网络安全职业规划

网络安全是一个日益增长的行业&#xff0c;对于打算进入或转行进入该领域的人来说&#xff0c;制定一个清晰且系统的职业规划非常重要。2025年&#xff0c;网络安全领域将继续发展并面临新的挑战&#xff0c;包括不断变化的技术、法规要求以及日益复杂的威胁环境。以下是一个关…

DocFlow票据AI自动化处理工具,提升企业票据数字化管理效能

随着全球化与信息化进程&#xff0c;企业的文件、信息、数据吞吐量不断增长&#xff0c;2020年以来&#xff0c;业务形势的变革再次加速了企业对先进的文档数字化管理解决方案需求。其中&#xff0c;票据处理始终面临着文件量大耗时、单据高度多样化、“淡旺季”周期波动性强、…

25页PDF | 企业级指标体系设计方法

一、前言 该PPT主要介绍了企业级指标体系的设计方法&#xff0c;包括指标设计的思路、具体实施步骤、以及指标体系的管理和应用。详细探讨了指标设计过程中可能遇到的困境&#xff0c;如权责不清晰、指标口径不统一、指标概念认知偏差等&#xff0c;并提出了相应的解决方案。具…