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),

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

相关推荐
计算机小白一个2 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
万事可爱^2 小时前
HDBSCAN:密度自适应的层次聚类算法解析与实践
算法·机器学习·数据挖掘·聚类·hdbscan
欧了1114 小时前
洛谷P9240 [蓝桥杯 2023 省 B] 冶炼金属
职场和发展·蓝桥杯·洛谷·蓝桥杯大学b组c语言
大数据追光猿4 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Dream it possible!5 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
夏末秋也凉5 小时前
力扣-回溯-46 全排列
数据结构·算法·leetcode
南宫生5 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴5 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
Leuanghing5 小时前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode
qy发大财5 小时前
加油站(力扣134)
算法·leetcode·职场和发展