文章目录
- 写在前面
- Tag
- 题目来源
- 题目解读
- 解题思路
- 方法一:排序
- 方法二:二分
- 方法三:计数排序
- 写在最后
写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【排序】【数组】
题目来源
面试经典150 | 274. H 指数
题目解读
有一个数组 citiations
,其中 citiations[i]
表示某一个研究员的论文 i
被引用的次数,你要做的是找出该名研究员的 h
指数。
h
指数,代表 “高引用次数”,表示有 h
篇论文且每一篇论文被引用了至少 h
次。
解题思路
方法一:排序
我们首先对数组 citiation
进行排序(一般不提及排序方式即升序还是降序排序,默认都是升序排序),然后对排序后的 citiation
从大到小进行遍历。
初始化 h = 0
,h
表示的是被引用了 h
次的论文数量,我们在遍历的过程中,如果 citiation[i] > h
表明我们找到了 h+1
篇至少被引用了 h+1
次的论文,这时候更新 h
为 ++h
。我们就这样遍历数组,直到 h
不再增加,最后返回 h
即为最终的答案。
实现代码
class Solution {
public:
int hIndex(vector<int>& citations) {
sort(citations.begin(), citations.end());
int h = 0, i = citations.size() - 1;
while (i >= 0 && citations[i] > h) {
++h;
--i;
}
return h;
}
};
复杂度分析
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),
n
n
n 为数组 citiation
的长度,这是排序的时间复杂度。
空间复杂度: O ( l o g n ) O(logn) O(logn),这是排序占用的额外空间。
方法二:二分
我们可以二分枚举答案,即 h
的数量,h
最少有 0
个,最多有 citiations.size()
个。
对于当前二分枚举的答案 mid
:
- 如果数组
citiations
中的论文被引用次数大于等于mid
的论文数大于等于mid
,我们右移二分枚举的下限,因为h
指数可能更大; - 否则,我们左移二分枚举的上限。
计算数组中论文被引用次数大于等于 mid
的论文数直接枚举计数就可以。
实现代码
class Solution {
public:
int hIndex(vector<int>& citations) {
int l = 0, r = citations.size();
while (l < r) {
int mid = (l + r + 1) >> 1;
int cnt = 0;
for (int x : citations) {
if (x >= mid) ++cnt;
}
if (cnt >= mid) l = mid;
else r = mid - 1;
}
return l;
}
};
复杂度分析
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),二分枚举的时间复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn),每次枚举中需要
O
(
n
)
O(n)
O(n) 的时间复杂度计算数组中论文被引用次数大于等于 mid
的论文数,因此总的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
空间复杂度: O ( 1 ) O(1) O(1),使用的额外空间仅仅是几个二分枚举时的辅助变量。
方法三:计数排序
其实还有一种排序的方法,计算排序是对方法一排序时间复杂度的优化。
具体地,我们使用一个数组 cnts
来记录被引用次数从 0
到 n
的对应的论文数量,其中 cnts[n]
表示引用次数大于 n
的论文数量。
首先,遍历数组 citiation
来更新 cnts
。最后,我们从后往前遍历数组 cnts
,我找到大于等于当前引用次数 i
的论文数量,一旦找到一个 i
直接返回,因为我要找的是最大的 h
。
实现代码
class Solution {
public:
int hIndex(vector<int>& citations) {
int n = citations.size();
vector<int> cnts(n + 1); // 当前引用次数的文章有几篇
for (int i = 0; i < n; i++) {
if (citations[i] >= n) {
cnts[n]++;
} else {
cnts[citations[i]]++;
}
}
int cnt = 0;
for (int i = n; i >= 0; i--) {
cnt += cnts[i];
if (cnt >= i) {
return i;
}
}
return 0;
}
};
复杂度分析
时间复杂度: O ( n ) O(n) O(n),计数排序的时间复杂度。
空间复杂度:
O
(
n
)
O(n)
O(n),使用的额外变量为统计被引用论文数的数组 cnts
。
写在最后
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。