leetcode274——H指数
- 暴力循环
- 代码分析
- 性能分析
- 方法1:排序加线性扫描
- 算法步骤:
- 方法2:计数排序(适用于引用次数有上限)
- 算法步骤:
题目链接:leetcode274_H指数
暴力循环
class Solution {
public:int hIndex(vector<int>& citations) {unordered_map<int, int> tmp;for (int i = 1; i <= citations.size(); i++){for (int j = 0; j < citations.size(); j++){if (citations[j] >= i){tmp[i]++;}}if (tmp[i] < i)return i - 1;}return citations.size();}};
代码分析
-
输入参数:
vector<int>& citations
:一个整数数组,表示每篇论文的引用次数。
-
变量声明:
unordered_map<int, int> tmp
:用于存储每个引用次数对应的论文数量。int i
和int j
:循环变量。
-
外层循环:
for (int i = 1; i <= citations.size(); i++)
:遍历从1到论文总数的所有可能的H指数值。
-
内层循环:
for (int j = 0; j < citations.size(); j++)
:遍历每篇论文的引用次数。if (citations[j] >= i)
:检查当前论文的引用次数是否大于等于当前假设的H指数值i。tmp[i]++
:如果满足条件,则增加计数器。
-
判断条件:
if (tmp[i] < i)
:如果当前假设的H指数值i对应的论文数量小于i,则返回i-1作为H指数。
-
返回值:
- 如果所有可能的H指数值都检查完毕,没有找到合适的H指数,则返回论文总数减1。
性能分析
- 这段代码的时间复杂度为O(n^2),其中n是论文的数量。这是因为有两个嵌套循环,每个循环都需要遍历整个数组。
- 空间复杂度为O(n),因为使用了一个哈希表来存储每个引用次数对应的论文数量。
改进建议
- 可以通过排序和二分查找来优化算法,将时间复杂度降低到O(n log n)。
- 使用计数排序或桶排序可以进一步优化到O(n)。
根据上述的改进建议,我们可以采取以下两种方法来优化H指数计算算法:
方法1:排序加线性扫描
这个方法的思想是先对引用次数进行排序,然后从高到低遍历排序后的数组,找到最大的i值,使得前i篇论文每篇至少被引用了i次。
算法步骤:
- 对引用次数数组进行降序排序。
- 从头开始遍历排序后的数组,对于每个索引
i
(从0开始),检查是否满足条件citations[i] >= i+1
。 - 如果条件不再满足,则返回当前的
i
作为H指数。 - 如果遍历结束仍未找到不满足条件的情况,则返回数组长度作为H指数。
时间复杂度
:O(n log n),因为排序的时间复杂度为O(n log n)。
空间复杂度
:O(1),如果使用原地排序算法的话,不需要额外的空间。
int hIndex(vector<int>& citations) {sort(citations.begin(), citations.end(), greater<int>()); // 按降序排序int i = 0;for (; i < citations.size() && citations[i] > i; ++i);return i;
}
方法2:计数排序(适用于引用次数有上限)
如果引用次数有一个合理的上限,比如不超过论文总数或某个固定的最大值,我们可以用计数排序来实现更高效的算法。该方法特别适合于引用次数不是非常大的情况。
算法步骤:
- 创建一个大小为n+1的数组
counts
用于计数,其中n是论文数量。 - 遍历
citations
数组,对于每个引用次数c
,如果c
大于等于n,则在counts[n]
中增加计数;否则,在counts[c]
中增加计数。 - 从后往前遍历
counts
数组,累计论文数量total
,直到total
大于等于当前索引i
,此时i
即为H指数。
时间复杂度
:O(n),因为我们只需要遍历一次citations
和一次counts
。
空间复杂度
:O(n),需要额外的counts
数组。
int hIndex(vector<int>& citations) {int n = citations.size();vector<int> counts(n + 1, 0);// 计算每个引用次数出现的频次for (int c : citations)counts[min(c, n)]++;// 从高往低累积论文数量,寻找H指数int total = 0;for (int i = n; i >= 0; --i) {total += counts[i];if (total >= i)return i;}return 0;
}
这两种方法都可以有效地减少原始代码中的冗余计算,并且提高了时间效率。