H指數定義:
H指數是用來綜合衡量學者發表論文的數量和質量的指標。
若某學者共發表N篇論文,H指數是指存在h篇論文至少每篇有h引用量,剩下的N-h篇中,每篇都不超過h引用量。
H指數也可以是期刊H指數,機構H指數,學者H指數等等。
一.排序法
復雜度
時間 O(NlogN) 空間 O(1)
思路
先將數組排序,我們就可以知道對於某個引用數,有多少文獻的引用數大於這個數。對於引用數citations[i],大於該引用數文獻的數量是citations.length - i,而當前的H-Index則是Math.min(citations[i], citations.length - i),我們將這個當前的H指數和全局最大的H指數來比較,得到最大H指數。
代碼
//排序按引用次數正序排序,並且可以舍棄為0的引用減少計算。
public class Solution {
public int hIndex(int[] citations) {
// 排序
Arrays.sort(citations);
int h = 0;
for(int i = 0; i < citations.length; i++){
// 得到當前的H指數
int currH = Math.min(citations[i], citations.length - i);
if(currH > h){
h = currH;
}
}
return h;
}
}
二.數組映射法
復雜度
時間 O(N) 空間 O(N)
思路
也可以不對數組排序,我們額外使用一個大小為N+1的數組stats。stats[i]表示有多少文章被引用了i次,這里如果一篇文章引用大於N次,我們就將其當為N次,因為H指數不會超過文章的總數。為了構建這個數組,我們需要先將整個文獻引用數組遍歷一遍,對相應的格子加一。統計完后,我們從N向1開始遍歷這個統計數組。如果遍歷到某一個引用次數時,大於或等於該引用次數的文章數量,大於引用次數本身時,我們可以認為這是H指數。之所以不用再向下找,因為我們要取最大的H指數。那如何求大於或等於某個引用次數的文章數量呢?我們可以用一個變量,從高引用次的文章數累加下來。因為我們知道,如果有x篇文章的引用大於等於3次,那引用大於等於2次的文章數量一定是x加上引用次數等於2次的文章數量。
代碼
public class Solution {
public int hIndex(int[] citations) {
int[] stats = new int[citations.length + 1];
int n = citations.length;
// 統計各個引用次數對應多少篇文章
for(int i = 0; i < n; i++){
stats[citations[i] <= n ? citations[i] : n] += 1;
}
int sum = 0;
// 找出最大的H指數
for(int i = n; i > 0; i--){
// 引用大於等於i次的文章數量,等於引用大於等於i+1次的文章數量,加上引用等於i次的文章數量
sum += stats[i];
// 如果引用大於等於i次的文章數量,大於引用次數i,說明是H指數
if(sum >= i){
return i;
}
}
return 0;
}
}
三 . 二分搜索法(優化)
復雜度
時間 O(logN) 空間 O(1)
思路
在升序的引用數數組中,假設數組長為N,下標為i,則N - i就是引用次數大於等於下標為i的文獻所對應的引用次數的文章數。如果該位置的引用數小於文章數,則說明則是有效的H指數,如果一個數是H指數,那最大的H指數一定在它的后面(因為是升序的)。根據這點就可已進行二分搜索了。這里min = mid + 1的條件是citations[mid] < n - mid,確保退出循環時min肯定是指向一個有效的H指數。
代碼
public class Solution {
public int hIndex(int[] citations) {
int n = citations.length;
if(n == 0) return 0;
int min = 0, max = citations.length - 1;
while(min <= max){
int mid = (min + max) / 2;
// 如果該點是有效的H指數,則最大H指數一定在右邊
if(citations[mid] < n - mid){
min = mid + 1;
// 否則最大H指數在左邊
} else {
max = mid - 1;
}
}
// n - min是min點的H指數
return n - min;
}
}
