LeetCode 274. H 指数
📌 题目描述
题目级别:中等
给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数 。
h 指数定义 :一名科研人员的 h 指数是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。
- 示例 1:
输入:citations = [3,0,6,1,5]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。由于研究者有 3 篇论文每篇 至少 被引用了 3 次,所以她的 h 指数是 3。
💡 破题思路:二分答案法 (Binary Search on Answer)
这道题除了常规的排序法以外,有一种极具"极客思维"的解法:二分答案。
为什么可以用二分?
因为 H 指数的成立条件具有绝对的单调性 。
假设我们在测试 H 指数是否能为 x:
- 如果满足条件(有 ≥x\ge x≥x 篇文章引用数 ≥x\ge x≥x),说明答案至少 是
x,可能更大。 - 如果不满足条件,说明答案必然小于
x。
算法流程:
- 观察题目给定的数据范围,引用次数
citations[i] <= 1000,且论文总数 N≤5000N \le 5000N≤5000。这意味着 H 指数最大不可能超过 1000。 - 我们定义搜索区间为
[0, 1000]。 - 每次取中间值
mid,遍历一次数组(check函数),统计引用数 ≥mid\ge mid≥mid 的论文数量。 - 如果满足要求,则收缩左边界
l = mid;如果不满足,收缩右边界r = mid - 1。 - 最终
l停下的位置,就是能满足条件的最大 H 指数。
⚠️ 极客细节避坑:
当我们在二分查找中写下 l = mid 时,计算 mid 的公式必须是向上取整的 mid = (l + r + 1) / 2。如果不加 1,当 l 和 r 只差 1 时,mid 会向下取整等于 l,导致区间无法缩小,从而陷入死循环。
💻 C++ 代码实现 (原汁原味作者版)
cpp
class Solution {
public:
int hIndex(vector<int>& citations) {
// 根据题目数据范围,H指数的最大值不可能超过 1000
int l = 0, r = 1000;
// 二分查找寻找最大的可行解
while (l < r)
{
// 向上取整,配合 l = mid 避免死循环
int mid = (l + r + 1) / 2;
// 如果当前的 mid 满足 H 指数条件,说明答案在 [mid, r]
if (check(citations, mid)) l = mid;
// 否则说明 mid 太大了,答案在 [l, mid - 1]
else r = mid - 1;
}
return l;
}
// 辅助函数:验证是否有至少 x 篇论文的引用量 >= x
// 💡 工程小贴士:在实际工业代码中,这里建议修改为 const vector<int>& citations
// 以避免每次调用 check 时产生高昂的数组拷贝开销
bool check(vector<int> citations, int x)
{
int cnt = 0;
for (int i = 0; i < citations.size(); i ++ )
{
if (citations[i] >= x) cnt ++ ;
}
return cnt >= x;
}
};