Leetcode经典题8--H指数

题目描述:

给你一个整数数组 citations ,其中 citationsi 表示研究者的第 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,然后将每个文章的引用次数排序,并且对数组进行从大到小的遍历,如果在遍历过程中找到当前值 citationsi>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),

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

相关推荐
Wang's Blog25 分钟前
PostgreSQL笔记49:向量检索核心算法、索引调优与过滤策略深度解析
笔记·算法·postgresql
疯狂打码的少年33 分钟前
【数据结构】交换类排序:冒泡与快速排序
数据结构·笔记·算法·排序算法
嵌入式阿蔡1 小时前
面试高频考点 01:volatile / 中断 / 堆栈 八股精讲
java·面试·职场和发展·嵌入式实时数据库
Nil2081 小时前
leetcode 108有序数组转换为二叉搜索树
数据结构·算法·leetcode
高频因子挖掘机1 小时前
QuantDash 成交量单位统一实战:从“手”到“股”的跨市场量化数据清洗全流程
后端·算法·github
hn小菜鸡1 小时前
LeetCode 763、划分字母区间
数据结构·算法·leetcode
Escalating_xu1 小时前
【C++ STL简介】从六大组件到容器、迭代器与算法协作
java·c++·算法
纪念 2292 小时前
算法二叉树(一)
算法
liulilittle2 小时前
llmx 学习手册 06 —— CPU 指令集优化(AVX-512 三层演进)
c++·学习·算法·ai·llm
土司大王3 小时前
LeetCode hot100——相交链表
算法·leetcode·链表