H 指数
今天的题目是力扣面试经典150题中的数组的中等难度题: H 指数。
题目链接:https://leetcode.cn/problems/h-index/description/?envType=study-plan-v2&envId=top-interview-150
题目内容
给定一位研究者论文被引用次数的数组 citations,数组中的每个元素 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回研究者的 H 指数。
根据维基百科上 h 指数的定义:h 代表"高引用次数" ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。
-
示例 1:
- 输入:
citations = [3,0,6,1,5] - 输出:
3
- 输入:
-
示例 2:
- 输入:
citations = [1,3,1] - 输出:
1
- 输入:
题目分析
题目要求我们根据论文引用次数数组计算研究者的 H 指数。那么我们首先要理解什么是H指数。
我们看看示例。
第一个示例输出3,我们简单找一下规律,数组中citations中大于等于3的元素是不是有3个?是不是有点符合题目中的h篇论文与h次。
我们再看第二个示例,输出了1。 数组citations中大于等于1的元素有三个啊,怎么输出1呢?
这里说明我们对目前题目内容的总结还不到位,继续分析。根据题目中指数定义,h的值三个条件都要满足,很明显我们简单分析过于简单。
这里我们有点陷入了误区,尤其是在第二个示例中,那么我们对示例重新分析,这次我们严格按照规则来分析,重点是两个h。
示例一分析
citations = [3,0,6,1,5]
我们从论文数开始,网上累加:
- h = 1,最少发布1篇论文,最少有1篇论文被引用1次。 发布5篇,有4篇被引用1次以上,h=1成立。
- h = 2,最少发布2篇论文,最少有2篇论文被引用2次。 发布5篇,有3篇被引用2次以上,h=2成立。
- h = 3,最少发布3篇论文,最少有3篇论文被引用3次。 发布5篇,有3篇被引用3次以上,h=3成立。
- h = 4,最少发布4篇论文,最少有4篇论文被引用4次。 发布5篇,有2篇被引用4次以上,h=4不成立。
- 后续更大的h值不会再成立了。
那么,示例一输出h = 3,是不是符合?
示例二分析
citations = [1,3,1]
参考示例一的分析,我们对示例二进行分析:
- h = 1,最少发布1篇论文,最少有1篇论文被引用1次。 发布3篇,有3篇被引用1次以上,h=1成立。
- h = 2,最少发布2篇论文,最少有2篇论文被引用2次。 发布3篇,有1篇被引用2次以上,h=2不成立。
- 后续更大的h值不会再成立了。
这么一看,示例二的输出1就明白了吧。
解题思路
这个题目简单粗暴的话就是直接暴力破解,暴力破解的思路比较直接简单,就是简单直接遍历,一个个开始试,就想示例分析的那样。但是这种方式对于大数组明显不现实,所以我们还得另想办法。
在上面的分析中,我们再次分析。可以发现解题需要对元素的值进行比较,并且需要抛弃或者说保留临界值另一边的数据。
那么我们直接排序,然后解答的时候,直接查看大于h值那边的元素个数,与h一比,不就行了?
也就是说我们需要一个方法,根据某个值来分开数组进行统计。
少侠,有没有听过二分法?
二分法
简单介绍一下二分法:
二分查找算法,又称折半查找算法,是一种在有序数组中查找特定元素的高效搜索方法。其核心思想是将目标值与数组中间元素进行比较,根据比较结果缩小搜索范围,然后重复这个过程,直到找到目标值或搜索范围为空。
基本步骤:
-
初始化:设置两个指针,一个指向数组的起始位置(通常记为low),另一个指向数组的结束位置(通常记为high)。
-
比较:取中间位置的元素(mid),将其与目标值进行比较。
-
判断:
- 如果中间元素等于目标值,搜索成功,返回该位置。
- 如果中间元素大于目标值,说明目标值位于数组的前半部分,更新high为mid - 1。
- 如果中间元素小于目标值,说明目标值位于数组的后半部分,更新low为mid + 1。
-
重复:继续步骤2和3,直到low大于high,此时搜索失败,目标值不在数组中。
实际算法代码
以下是使用上述思路的 Java 实现:
java
public class Solution {
public int hIndex(int[] citations) {
Arrays.sort(citations);
int n = citations.length;
int hIndex = 0;
for (int i = n - 1; i >= 0; i--) {
int h = n - i;
if (citations[i] >= h) {
hIndex = h;
} else {
break;
}
}
return hIndex;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] citations = {3, 0, 6, 1, 5};
int hIndex = solution.hIndex(citations);
System.out.println("H index: " + hIndex);
} }
结果
运行代码,测试通过:
提交到力扣,也正常通过:
总结
今天的题目使用了新的算法,二分法,本文只是简单的介绍了一下什么是二分法已经步骤。
相比与暴力解答,二分法明显时间复杂度更低,并且使用时对大数组也相对支持。大家可以自己另外学习二分法,也可以等我后面总结学习。
加油!!!