📟作者主页:慢热的陕西人
🌴专栏链接:力扣刷题日记
📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言
文章目录
题目链接
题目描述
给你一个整数数组
citations
,其中citations[i]
表示研究者的第i
篇论文被引用的次数。计算并返回该研究者的h
指数 。根据维基百科上 h 指数的定义:
h
代表"高引用次数" ,一名科研人员的h
指数 是指他(她)至少发表了h
篇论文,并且 至少 有h
篇论文被引用次数大于等于h
。如果h
有多种可能的值,h
指数 是其中最大的那个。
方法一:排序
解题思路
理解了题意以后我们可以对h数总结为如下几点:
a. 0 <= h < citations[i].size() : h数一定是小于论文数量的
b. h = min(i, 当前数组中第i大的元素):即至少 有
h
篇论文被引用次数大于等于h
基于上述两点我们可以先将数组排序然后遍历数组即可得到答案!
代码
C++
// 自定义比较函数,用于降序排序
bool compareDescending(int a, int b) {
return a > b;
}
class Solution {
public:
int hIndex(vector<int>& citations) {
sort(citations.begin(), citations.end(), compareDescending);
int h = 1;
int ret = 0;
for(int i = 0; i < citations.size(); ++i) {
h = min(i + 1, citations[i]);
ret = max(h, ret);
}
return ret;
}
};
复杂度分析
时间复杂度:
O(nlogN)
,先使用了sort进行了排序,然后在遍历数组找出答案
空间复杂度: ``O(logN),由于sort的空间复杂度是
O(logN)`
方法二:计数排序
解题思路
根据方法一思路我们可以理解为我们将原数组排序后再进行遍历即可,所以我们可以使用计数排序来优化,因为计数排序是一个时间复杂度为线性的排序方法!
这里的思路和方法一略有不同,首先第一个循环内是计数排序的排序过程,第二个循环内从后往前遍历计数排序的数组counter,每次将counter[i]累加起来,当tot >= i的时候则i为答案。这里的原理可以理解为tot为至少被引用i次的论文数量总和,然后i是被引用次数,当这两个值相交时就为h数。
代码
cpp
class Solution {
public:
int hIndex(vector<int>& citations) {
int n = citations.size(), tot = 0;
vector<int> counter(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)
,基于计数排序的时间复杂度为O(N)
空间复杂度:O(N)
,计数排序的数组的长度为源数组的数据范围
方法三:二分搜索
解题思路
为什么会联想到使用二分搜索?
我们不妨换一个角度思考整个问题,基于方法1的理解我们先将原数组进行了排序,我们将citations[i]和i理解为两个函数即:
y 1 = c i t a t i o n s [ i ] , y 2 = i y_1=citations[i] ,y_2=i y1=citations[i],y2=i然后这两个函数分别是单调递减和单调递增的,所以如果他们有交点的话那么交点处的citations[i]就是h指数(这是大多数情况下),实际实现的情况会有一些额外的情况,例如没有交点那么h指数就是论文个数总和等
代码
cpp
class Solution {
public:
int hIndex(vector<int>& citations) {
if(citations.size() == 1) return citations[0] >= 1 ? 1 : 0;
std::sort(citations.begin(), citations.end(),
[](int a, int b) { return a > b; });
int right = citations.size() - 1;
int left = 0;
while (left < right) {
int mid = (left + right + 1) >> 1;
if(mid > citations[mid]) {
right = mid - 1;
} else if(mid < citations[mid]) {
left = mid;
} else {
return citations[mid];
}
}
return min(citations[left], left + 1);
}
};
复杂度分析
时间复杂度:
O(nlogN)
排序 + 二分
空间复杂度:O(1)
,使用了常数个额外的变量