在问 · 算法题解

274. H 指数

题目描述

输入一个整数数组 citations,citations[i] 是某位研究者第 i 篇论文被引用的次数。

H 指数的定义:若存在 h,使得这位研究者至少有 h 篇论文,每篇都被引用了不少于 h 次,那么 h 就是一个可行值。所有可行值中最大的那个就是 H 指数。

计算并返回这位研究者的 H 指数。

示例 1
输入:citations = [3,0,6,1,5]
输出:3

解释:一共 5 篇论文,有 3 篇的引用数不少于 3(6、5、3),但找不到 4 篇引用数都不少于 4 的论文,所以答案是 3。

示例 2
输入:citations = [1,3,1]
输出:1

解释:至少被引用 1 次的论文有 3 篇,但被引用不少于 2 次的只有 1 篇,答案是 1。

数据范围

  • n == citations.length
  • 1 <= n <= 5000
  • 0 <= citations[i] <= 1000

解题思路:排序

把引用次数从大到小排序。排序后第 i 篇(从 0 开始)是引用第 i+1 多的论文:如果它的引用数 c >= i+1,说明前 i+1 篇每篇都至少被引 i+1 次,h 至少是 i+1。一旦某篇 c < i+1,后面的论文引用只会更少、需要的门槛只会更高,不可能再满足,直接停止。

为什么正确

处理到下标 i 时,h = i 表示前 i 篇论文每篇引用都 >= i,即 h 指数至少为 i。

复杂度分析

时间 O(n log n)(排序),空间 O(1) 或排序所需的 O(log n)。

易错点

比较的是 c >= i+1,不是 c >= i;全部论文都满足时 h 等于论文总数 n,不会超过 n;若升序排序,要用 n-i 而不是 i+1 作为门槛。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def hIndex(self, citations: List[int]) -> int:
        citations.sort(reverse=True)
        h = 0
        for i, c in enumerate(citations):
            if c >= i + 1:
                h = i + 1
            else:
                break
        return h

载入编辑器,自己跑一遍 →

其他解法

排序后从大到小扫一遍就能找到 h,耗时主要在排序;计数排序利用 h ≤ n 把值域压到 [0, n],线性时间完成。

解法 2:计数排序 时间 O(n),空间 O(n)

H 指数不会超过论文数 n,所以引用次数大于 n 的都按 n 计。用 cnt[c] 统计引用次数为 c 的论文数。h 从 n 往下枚举,累加 cnt[h] 得到引用次数至少为 h 的论文数,第一次累计值 ≥ h 时 h 就是答案。

利用答案上界为 n,把排序降到线性。需要 O(n) 的计数数组,也要想到“超过 n 的引用次数可以截断”。

class Solution:
    def hIndex(self, citations: List[int]) -> int:
        n = len(citations)
        cnt = [0] * (n + 1)
        for c in citations:
            cnt[min(c, n)] += 1
        total = 0
        for h in range(n, -1, -1):
            total += cnt[h]
            if total >= h:
                return h
        return 0

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →