根据 H 指数的定义,如果当前 H 指数为 h 并且在遍历过程中找到当前值 citations[i]>h,则说明我们找到了一篇被引用了至少 h+1 次的论文,所以将现有的 h 值加 1。继续遍历直到 h 无法继续增大。最后返回 h 作为最终答案。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
//C++ 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; } };
1 2 3 4 5 6 7 8 9 10 11 12
//Java 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 的长度。即为排序的时间复杂度。
//C++ 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; } };
//Java public class Solution { public int hIndex(int[] citations) { 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 的长度。需要创建长度为 n+1 的数组 counter。
(3)二分搜索
思路及算法
我们需要找到一个值 h,它是满足「有 h 篇论文的引用次数至少为 h」的最大值。小于等于h的所有值 x 都满足这个性质,而大于 h 的值都不满足这个性质。同时因为我们可以用较短时间(扫描一遍数组的时间复杂度为 O(n),其中 n 为数组 citations 的长度)来判断 x 是否满足这个性质,所以这个问题可以用二分搜索来解决。
设查找范围的初始左边界 left 为 0,初始右边界 right 为 n。每次在查找范围内取中点 mid,同时扫描整个数组,判断是否至少有 mid 个数大于 mid。如果有,说明要寻找的 h 在搜索区间的右边,反之则在左边。