当前位置: 首页 > news >正文

leetcode274:H指数(计数排序)从 O(N²) 到 O(N) 的思维上升

文章目录

  • 一、 题目描述
  • 二、 思维一:解析 H 指数的定义
  • 三、 思维二:从暴力验证到 O(N²) 解法
  • 四、 思维三:空间换时间,计数排序
  • 五、 最佳实践:代码实现与深度解析
  • 六、 复杂度分析

274. H 指数 - 力扣(LeetCode),【难度:中等;通过率: 46.5%】,这道题的难点不在于需要多复杂的算法,而在于如何真正 理解题意,这个题意有些绕,先理解题意,写出来 O(N²) 的解法/思路,我们再考虑下一步优化为 O(N)

一、 题目描述

给你一个整数数组 citations,表示研究者的 n 篇论文被引用的次数。研究者的 h 指数 是指他有 h 篇论文分别被引用了至少 h

请计算并返回该研究者的 h 指数

示例:

输入: citations = [3,0,6,1,5]
输出: 3解释:
研究者有 5 篇论文,引用次数分别为 [3,0,6,1,5]
由于研究者有 3 篇论文的引用次数至少为 3 (分别是 3, 6, 5),
其余 2 篇论文的引用次数不多于 3 (分别是 0, 1),
所以她的 h 指数是 3

二、 思维一:解析 H 指数的定义

我们首先要做的,就是把这个有点绕的定义彻底搞明白

H 指数:一个整数 h,满足至少h 篇论文的引用次数至少h。题目要求我们找到这个 h最大值

让我们用一个具体的例子来验证。对于 citations = [3,0,6,1,5],我们来检查 h=3 是否满足条件:

  1. 第一个条件:“至少有 h 篇论文”,这里 h=3
  2. 第二个条件:“引用次数至少为 h”,这里 h=3

合起来就是:“至少有 3 篇论文,它们的引用次数都至少为 3

我们来数一下:[3, 6, 5] 这三篇论文的引用次数都 >= 3。我们找到了 3 篇,满足了“至少 3 篇”的要求。所以,h=3 是一个有效的 h 指数

我们再试试 h=4:“至少有 4 篇论文,它们的引用次数都至少为 4”
我们数一下:只有 [6, 5] 这两篇论文的引用次数 >= 4。我们只找到了 2 篇,不满足“至少 4 篇”的要求。所以 h=4 不是一个有效的 h 指数

既然 h=4 不行,更大的 h=5h=6 肯定也不行。因此,h=3 就是最大的那个,也就是最终答案


三、 思维二:从暴力验证到 O(N²) 解法

通过上面的分析,我们发现可以把问题转化为:

寻找一个最大的 h,使得 (引用次数 >= h 的论文数量) >= h

一个最朴素的想法是:

  1. h 的可能取值范围是什么?最多有 n 篇论文,所以 h 不可能超过 nh取值范围是 [0, n]
  2. 我们可以从大到小(从 n0)来猜测 h 的值
  3. 对于每一个猜测的 h,我们都遍历一次 citations 数组,统计出有多少篇论文的引用次数 >= h
  4. 如果这个统计数量也 >= h,那么我们就找到了答案,因为我们是从大到小猜的,第一个满足条件的一定是最大的

这个思路可以写成如下的伪代码:

n = citations.length
for h from n down to 0:count = 0for c in citations:if c >= h:count++if count >= h:return h

这个解法是正确的,但它的时间复杂度是 O(N²),因为外层循环 h 最多 N 次,内层循环遍历 citations 又是 N 次。对于这道题,通常会超时


四、 思维三:空间换时间,计数排序

O(N²) 的瓶颈在于,对于每个猜测的 h,我们都重复地遍历了整个 citations 数组。如何能快速地知道“有多少篇论文的引用次数不小于 h”呢?

这就是计数思想发挥作用的地方。我们可以预处理 citations 数组,用一个计数器数组来记录信息

关键 1:我们关心的引用次数有边界吗?
是的。因为 h 最大只能是 n,所以一篇论文被引用了 n 次、n+1 次,还是 1000 次,对于判断 h 是否满足条件来说,效果是完全一样的。例如,要判断 h=5 是否成立,一篇引用了 1000 次的论文和一篇引用了 5 次的论文,都同样满足 c >= 5 的条件
所以,我们可以将所有引用次数大于 n 的论文,都视作引用了 n 次。这极大地缩小了我们需要关心的引用次数范围,即 [0, n]

构建计数器数组
我们可以创建一个大小为 n+1 的数组 counts,其中 counts[i] 记录了引用次数恰好i 的论文有多少篇

int n = citations.length;
int[] counts = new int[n + 1];
for (int c : citations) {if (c > n) {counts[n]++;} else {counts[c]++;}
}
// 这可以简化为一行:
// counts[Math.min(c, n)]++;

关键 2:后缀和的妙用
现在我们有了 counts 数组。当我们想知道“引用次数至少i 的论文数量”时,我们只需要计算 counts[i] + counts[i+1] + ... + counts[n] 即可。这是一个后缀和

结合“从大到小猜测 h”的思路,我们可以非常高效地得到答案:

  1. i = n 开始向下遍历
  2. 维护一个变量 total,表示引用次数至少i 的论文总数
  3. in 变为 n-1 时,total 的变化是 total_new = total_old + counts[n-1]
  4. 在每一步,我们都检查 total >= i 是否成立。第一个成立的 i 就是答案

这个过程完美地将时间复杂度降到了 O(N)


五、 最佳实践:代码实现与深度解析

一种最佳实践代码:

class Solution {public int hIndex(int[] citations) {int n = citations.length;// 步骤 1: 创建计数器数组,利用关键洞察 1 进行计数// counts[i] 存储引用次数为 i 的论文篇数// 所有引用次数 > n 的论文,都当作 n 次来统计int[] counts = new int[n + 1];for (int c : citations) {counts[Math.min(c, n)]++;}// 步骤 2: 从大到小遍历 h 的可能值,并利用后缀和思想int total = 0; // total 记录引用次数 >= i 的论文总数for (int i = n; i >= 0; i--) {// 累加当前引用次数的论文数,得到后缀和total += counts[i];// 检查是否满足 h 指数的定义// total: 论文数量// i: 引用次数// total >= i  =>  有 total 篇论文的引用次数 >= iif (total >= i) {// 因为 i 是从大到小遍历的,第一个满足条件的 i 就是最大的 hreturn i;}}return 0; // 正常情况下不会执行到这里}
}

提交结果:

在这里插入图片描述


六、 复杂度分析

  • 时间复杂度O(N) 第一个 for 循环遍历 citations 数组,耗时 O(N)。第二个 for 循环遍历 counts 数组,耗时 O(N)。总时间复杂度为 O(N + N) = O(N)
  • 空间复杂度O(N) 我们使用了一个大小为 n+1counts 数组
http://www.dtcms.com/a/353201.html

相关文章:

  • 重学JS-004 --- JavaScript算法与数据结构(四)JavaScript 表单验证
  • Linux 下 Nginx 服务器从入门到精通:安装、配置、实战与性能优化​
  • mfc中操作excel
  • 关于国产 RAC 和分布式研讨
  • 【DBCExcelConvent】CAN报文解析辅助工具之DBC与Excel互转
  • 使用k8s实现部署MySQL的主从复制
  • 【LeetCode - 每日1题】求网格最长V形对角线段的长度
  • 页面跳转html
  • HTML响应式设计的颜色选择器,适配各种屏幕尺寸
  • rk3588 ubuntu20.04屏幕显示问题解决
  • CPU-IO-网络-内核参数的调优
  • AOSP 编译系统 (Android build system)
  • 嵌入式C语言进阶:位操作的艺术与实战
  • 【测试】pytest测试环境搭建
  • Linux 离线环境下 Anaconda3 与核心机器学习库(scikit-learn/OpenCV/PyTorch)安装配置指南
  • 解决Visual Studio中UWP设计器无法显示的问题:需升级至Windows 11 24H2
  • 【SQL优化案例】SQL执行频率问题与优化效果预期
  • NumPy/PyTorch/C char数组内存排布
  • 网站防爆破安全策略分析
  • python项目开发:创建虚拟环境
  • 利用机器学习优化Backtrader策略原理与实践
  • 深入解析函数栈帧创建与销毁
  • 斯塔克工业技术日志:用基础模型打造 “战甲级” 结构化 AI 功能
  • 预测模型及超参数:1.传统机器学习:SVR与KNN
  • 网页版云手机怎么样
  • Enduro 克隆游戏 — 基于 HTML、CSS 与 JavaScript 的完整教程模板
  • 23种设计模式——单例模式(Singleton)​详解
  • 金仓数据库文档系统全面升级:用户体验焕然一新
  • CPU、IO、网络与内核参数调优
  • Linux 性能调优实战:CPU、磁盘 I/O、网络与内核参数