面试经典算法150题系列-h指数

h指数

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h指数

根据维基百科上 h 指数的定义h 代表"高引用次数" ,一名科研人员的 h指数 是指他(她)至少发表了 h 篇论文,并且 至少h 篇论文被引用次数大于等于 h 。如果 h有多种可能的值,h 指数是其中最大的那个。

示例 1:

输入:citations = [3,0,6,1,5]
输出:3 
解释:给定数组表示研究者总共有 5篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5次。由于研究者有 3 篇论文每篇 至少被引用了 3次,其余两篇论文每篇被引用 不多于 3次,所以她的 h指数是 3。

示例 2:

复制代码
输入:citations = [1,3,1]
输出:1

实现思路:

要计算一个研究者的 h 指数,你可以按照以下步骤进行:

  1. 排序:将论文引用次数从高到低进行排序。

  2. 计算 h 指数:从排序后的数组的最后一个元素(即引用次数最高的论文)开始,向前遍历数组:

    • 维护一个计数器 h,初始值为 1。
    • 对于数组中的每个元素 citations[i]
      • 如果 citations[i] 大于或等于 h,则 h 加 1。
      • 如果 citations[i] 小于 h,则停止增加 h,因为此时已经不能满足 h 指数的定义(即每篇论文至少被引用 h 次)。
  3. 返回 h 指数 :返回计算出的 h 值。

思路模拟:以citations = [3,0,6,1,5]为例(大家可以在图纸上画一遍模拟一下)

首先我们进行从高到低排序得到 6,5,3,1,0.然后从数组最后往前开始遍历数组。判断citations[i]是否大于等于h

第一次遍历:0 (数组元素)< 1(h的值),因此不满足条件,结束当前遍历。

第二次遍历:1 = 1,满足条件,h++,进行下一次遍历。

第三次遍历:3 > 2 满足条件,h++,进行下一次遍历。

第四次遍历:5 > 3 满足条件,h++,进行下一次遍历。

第五次遍历: 6 > 4 满足条件,h++,循环结束。

然后因为我们h是从1开始,最后一次满足条件时多加了一次,在我们返回时则需要减1.

实现代码:

java 复制代码
public  int hIndex(int[] citations) {
        //数组从高到低进行排序  Arrays.sort函数
        Arrays.sort(citations);
        int h=1;  //定义h指数
        //对数组进行遍历,从后往前,如果数组元素大于等于h,则为h指数,h++
        for (int i = citations.length-1; i >=0 ; i--) {
            if (citations[i] >= h){
                h++;
            }else {
                break;
            }
        }
        return h-1;//因最后一次符合条件的判断多加了一次,因此需要减一
    }

实现思路二:使用一个计数数组来统计每个引用次数的论文数量,然后通过反向迭代来确定 h 指数。

实现代码:

java 复制代码
public int hIndex(int[] citations) {
    int n = citations.length; // 1. 获取输入数组 citations 的长度。
    int[] count = new int[n + 1]; // 2. 创建一个长度为 n + 1 的数组 count,用于统计每个引用次数的论文数量。数组索引从 0 到 n,其中索引 i 表示引用次数为 (i + 1) 的论文数量。

    for (int num : citations) { // 3. 遍历数组 citations 中的每个引用次数 num。
        count[Math.min(num, n)]++; // 4. 对于每个引用次数 num,如果 num 大于 n,则它将与 n 一样被视为 n。然后,对应索引的 count 数值增加 1。
    }

    int total = 0; // 5. 初始化总论文数量计数器 total 为 0,用于计算至少被引用特定次数的论文总数。

    for (int i = n; ; i--) { // 6. 开始一个无限循环,从 n 开始递减至 0。循环条件为空,表示无限迭代,但内部的逻辑将决定何时退出循环。
        total += count[i]; // 7. 将当前索引 i 对应的引用次数的论文数量加到 total 上。这表示统计了至少被引用 i 次的论文数量。
        if (total >= i) { // 8. 如果 total 大于等于当前的索引 i,根据 h 指数的定义,我们找到了满足条件的最小 h 值。
            return i; // 9. 返回索引 i 作为 h 指数的值。此时,我们知道至少有 i 篇论文被引用了至少 i 次。
        }
    }
}

代码逻辑的核心在于:

  • 使用 count 数组来统计每个引用次数的论文数量,数组索引 i 表示引用次数为 (i + 1) 的论文数量。
  • 通过反向迭代 count 数组,累加至少被引用特定次数的论文总数。
  • 当累加的论文总数 total 大于等于当前的引用次数 i 时,满足 h 指数的定义,返回当前的 i 作为 h 指数。

这种方法的时间复杂度是 O(n),其中 n 是数组 citations 的长度,因为它只需要对数组进行两次遍历:一次用于统计引用次数,一次用于计算 h 指数。这种方法避免了对原始数组进行排序,因此在某些情况下可能更高效。

知识补充:

1.Arrays.sort()函数

Arrays.sort() 是 Java 中的一个方法调用,用于对整数数组 进行排序。这个方法是基于 TimSort 算法实现的,TimSort 是一种结合了归并排序和插入排序的高效排序算法,它在多种情况下都能提供很好的性能。(关于归并排序和插入排序如果有需要,后期我出两期内容)

以下是关于 Arrays.sort() 方法的一些关键点:

  1. 原地排序Arrays.sort() 对数组进行原地排序,意味着它直接修改传入的数组,而不是创建一个新的排序数组。

  2. 时间复杂度 :对于大多数情况,Arrays.sort() 的平均时间复杂度是 O(n log n),其中 n 是数组的长度。

  3. 稳定性Arrays.sort() 是一个稳定的排序算法,这意味着相等的元素在排序后保持它们原始的顺序。

  4. 使用场景:当你需要对数组中的元素进行排序时,可以使用这个方法。例如,你可以对整数、浮点数、对象数组等进行排序。

  5. 重载方法Arrays.sort() 提供了多个重载版本,支持不同类型的数组排序,包括原始数据类型数组(如 int、float 等)和对象数组。

  6. 自定义排序 :对于对象数组,你可以传递一个 Comparator 实例作为参数,以自定义排序逻辑。

  7. 并行排序 :从 Java 8 开始,Arrays.sort() 默认使用并行排序(如果底层的硬件支持),这可以提高大数据集的排序速度。

  8. 异常处理 :如果数组包含 null 或排序器(Comparator)抛出异常,则 Arrays.sort() 会抛出 NullPointerException 或其他相关异常。

相关推荐
劲夫学编程35 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪37 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown6 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错7 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny8 小时前
计算网络信号
java·算法·华为
景鹤8 小时前
【算法】递归+深搜:814.二叉树剪枝
算法