Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index.
According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each."
Example:
Input: citations = [3,0,6,1,5] Output: 3 Explanation: [3,0,6,1,5] means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, her h-index is 3.
Note: If there are several possible values for h, the maximum one is taken as the h-index.
解法一,O(nlogn):
上来先排序,这么做的理由显而易见,因为排过序之后就会建立引用数和文章数的关系。比如例子中,排过序之后就变成了{0, 1, 3, 5, 6}。如果倒序遍历排序过的数组就会获得如下信息:第五篇文章被引用6次,证明有五篇文章引用次数小于或等于它,换句话说就是有一篇文章引用次数大于或等于5。而H指数要求有h篇文章至少被引用h次,那么证明这个引用次数太大了,所以继续向引用次数较小的方向遍历。当遍历到第四篇文章的时候,被引用次数是5次,证明有两篇文章的引用次数大于等于5。再继续,第三篇被引用三次,那么就是有三篇文章引用次数大于等于3次。而再继续向下遍历的时候,知道有四篇文章的引用数大于等于1,已经不满足条件了。所以其实对于例子来说,H指数已经求出来了,就是3,即结果出现在介于满足和不满足定义之间的那次遍历。再想一下特殊的情况,假如输入是{3, 3, 3, 5, 6}呢?遍历到第三篇的时候得知至少有三篇文章引用次数大于等于3,而到了第二篇的时候就是4篇文章引用次数大于等于3,H指数就比定义大了。所以当文章数第一次达到临界值的时候,H指数不应该再增加了。体现在代码上就是严格的大于号,而不是大于等于号。如果想不明白,可以想一个{0, 0, 0}或{1, 1, 1}的例子。详见下文代码。
解法二,O(n):
解法一排序的目的就是为了建立引用数和文章数的关系。有没有办法不排序,或者至少不通过比较排序而建立这个关系呢?因为比较排序的时间复杂度至少也是线性对数级别,非比较排序是可以优化到线性时间复杂度的。这个时候就想起了计数排序。通过计数,直接统计每个引用次数下面有多少文章。而再通过扫描累加,就会知道大于等于某一个引用次数的文章是多少。当找到第一个文章数大于等于引用数的计数点,即找到了所求。这里要注意如果一篇文章的引用数大于等于总文章数,那么它对H指数的贡献最多是n次,即文章总数。因为H指数是不可能大于总文章数的。所以在计数的时候把这类文章单独放到计数数组最后面,再加上特别的判断即可。详见代码。
解法一(Java)
class Solution { public int hIndex(int[] citations) { if (citations == null || citations.length == 0) return 0; Arrays.sort(citations); int res = 0; for (int i = citations.length - 1; i >= 0; i--) if (citations[i] > res) res++; return res; } }
解法二(Java)
class Solution { public int hIndex(int[] citations) { int n = citations.length; int[] count = new int[n + 1]; for (int i = 0; i < n; i++) { if (citations[i] >= n) count[n]++; //统计引用数比总文章数还多的文章数目 else count[citations[i]]++; //统计每个引用次数下有多少篇文章 } if (count[n] >= n) return n; //如果每篇文章的引用数都比文章数多,那H指数最多也只能是文章数n for (int i = n - 1; i >= 0; i--) { count[i] += count[i + 1]; //不要忘了这里的i一直是引用次数,所以这一步在统计大于等于i的文章总数,即逐个累加大于等于i的计数 if (count[i] >= i) return i; //一旦找到满足条件的引用次数,即返回 } return 0; } }