Leetcode经典题8--H指数

题目描述:

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

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

输入输出示例 :

**输入:**citations = [3,0,6,1,5]

**输出:**3

**解释:**给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。

由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。

解题方案:

方式一:排序

算法思想: 首先我们将初始的H指数h设置为0,然后将每个文章的引用次数排序,并且对数组进行从大到小的遍历,如果在遍历过程中找到当前值 citations[i]>h,那么对于i后面的n-i-1个数,肯定都大于h,可定有h+1

举例说明:

例如对于下面的数组

3,0,6,1,5

首先进行排序

0 1 3 5 6

然后我们从后往前遍历(数值上从大到小遍历)

初始h=0 此时指向数值6 6>0 所以h=1 至少有1个文章的引用次数大于1

指向数值5 5>1 所以h=2 此时已经倒序遍历了2个数,如果当前数大于2,那么至少有2个文章的引用次数(两篇遍历过的文章的引用次数5次,和6次)大于2

指向数值3 3>2 所以h=3 此时已经倒序遍历了3个数,如果当前数大于3,那么至少有3个文章的引用次数(3篇遍历过的文章的引用次数3次 5次,和6次)大于2

实现代码:

复制代码
class Solution {
    public int hIndex(int[] citations) {
        Arrays.sort(citations);//将数组排序
        int h = 0, i = citations.length - 1; //从后往前遍历
        while (i >= 0 && citations[i] > h) {
            h++; 
            i--;
        }
        return h;
    }
}

复杂度分析

时间复杂度:O(nlogn),

其中 n 为数组 citations 的长度。即为排序的时间复杂度。

空间复杂度:O(logn),

其中 n 为数组 citations 的长度。即为排序的空间复杂度。

方法二:计数排序

算法思想: 使用计数排序算法,新建并维护一个数组 counter 用来记录当前引用次数的论文有几篇。

根据定义,我们可以发现 H 指数不可能大于总的论文发表数,所以对于引用次数超过论文发表数的情况,我们可以将其按照总的论文发表数来计算即可。这样我们可以限制统计引用次数的数组大小为**[0,n](**其中 n 为总的论文发表数),使得计数排序的时间复杂度降低到 O(n)。

最后我们可以从后向前遍历数组 counter,对于每个 0≤i≤n,在数组 counter 中得到大于或等于当前引用次数 i 的总论文数。当我们找到一个 H 指数时跳出循环,并返回结果。

实现代码:

复制代码
class Solution {
    public int hIndex(int[] citations) {
        //n记录数组长度和最多的引用次数 tot记录大于某个引用次数的论文数
        int n=citations.length,tot=0;
        int[] counter=new int[n+1];//每个引用次数对应的论文数
        for(int i=0;i<n;i++){
            if(citations[i]>=n){
                counter[n]++;
            }else{
                counter[citations[i]]++;
            }
        }

        for(int i=n;i>=0;i--){
            tot+=counter[i];
            if(tot>=i){
                return i;
            }
            
        }
       return 0;
    }
}

复杂度分析:

时间复杂度:O(n),

其中 n 为数组 citations 的长度。需要遍历数组 citations 一次,以及遍历长度为 n+1 的数组 counter 一次。

空间复杂度:O(n),

其中 n 为数组 citations 的长度。需要创建长度为 n+1 的数组 counter。

方式三:二分搜索

算法思想: 我们需要找到一个值 h,它是满足「有 h 篇论文的引用次数至少为 h」的最大值。小于等于 h 的所有值 x 都满足这个性质,而大于 h 的值都不满足这个性质。同时因为我们可以用较短时间(扫描一遍数组的时间复杂度为 O(n),其中 n 为数组 citations 的长度)来判断 x 是否满足这个性质,所以这个问题可以用二分搜索来解决。

设查找范围的初始左边界 left 为 0,初始右边界 right 为 n。每次在查找范围内取中点 mid,同时扫描整个数组,判断是否至少有 mid 个数大于 mid。如果有,说明要寻找的 h 在搜索区间的右边,反之则在左边。

实现代码

复制代码
class Solution {
    public int hIndex(int[] citations) {
        int left=0,right=citations.length;
        int mid=0,cnt=0;
        while(left<right){
            // +1 防止死循环
            mid=(left+right+1)>>1;
            cnt=0;
            for(int i=0;i<citations.length;i++){
                if(citations[i]>=mid){
                    cnt++;
                }
            }
            if(cnt>=mid){
                // 要找的答案在 [mid,right] 区间内
                left=mid;
            }else{
                // 要找的答案在 [0,mid) 区间内
                right=mid-1;
            }
        }
        return left;
    }
}

复杂度分析

时间复杂度:O(nlogn),

其中 n 为数组 citations 的长度。需要进行 logn 次二分搜索,每次二分搜索需要遍历数组 citations 一次。

空间复杂度:O(1),

只需要常数个变量来进行二分搜索。

相关推荐
Excuse_lighttime几秒前
排序数组(快速排序算法)
java·数据结构·算法·leetcode·eclipse·排序算法
潘小安19 分钟前
『译』迄今为止最强的 RAG 技术?Anthropic 的上下文检索与混合搜索
算法·llm·claude
kessy133 分钟前
安全与续航兼备的“国密芯”——LKT6810U
算法
leo__52040 分钟前
基于经验模态分解的去趋势波动分析(EMD-DFA)方法
人工智能·算法·机器学习
lzptouch1 小时前
AdaBoost(Adaptive Boosting)算法
算法·集成学习·boosting
南方的狮子先生1 小时前
【数据结构】(C++数据结构)查找算法与排序算法详解
数据结构·c++·学习·算法·排序算法·1024程序员节
前进的李工2 小时前
LeetCode hot100:560 和为k的子数组:快速统计法
python·算法·leetcode·前缀和·哈希表
在等晚安么2 小时前
力扣面试经典150题打卡
java·数据结构·算法·leetcode·面试·贪心算法
AndrewHZ3 小时前
【图像处理基石】图像滤镜的算法原理:从基础到进阶的技术解析
图像处理·python·opencv·算法·计算机视觉·滤镜·cv
lxmyzzs3 小时前
【图像算法 - 30】基于深度学习的PCB板缺陷检测系统: YOLOv11 + UI界面 + 数据集实现
人工智能·深度学习·算法·yolo·缺陷检测