11.H指数
标签
排序 数组 计数排序
题目描述
给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。
根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。
原题链接 H指数
解法一:排序
使用普通排序算法降序排序,只要当前的文章引用次数大于当前的h指数(H指数从零开始)即可;
public int hIndex(int[] citations) {
//当前文章被引用次数
int currentArticleIndex=0;
//h指数,初始时认为当前发表了h个论文,并且至少有h个论文的引用次数大于等于h;
int h=0;
//对数组进行排序
Arrays.sort(citations);
//反转数组
reverse(citations,0,citations.length-1);
//遍历从高到低
for (;currentArticleIndex<citations.length;currentArticleIndex++){
//表示已经有一篇论文的引用次数超过0了;
if(citations[currentArticleIndex]>h){
h++;
}
}
return h;
}
public void reverse(int[] arr,int left,int right){
while (left<right){
int t=arr[left];
arr[left]=arr[right];
arr[right]=t;
left++;
right--;
}
}
解法二:计数排序
由于解法一中最终的时间复杂度和排序算法有关,因此可以优化排序算法为计数排序,计数排序具有线性的时间复杂度;
什么是计数排序
计数排序属于典型的用空间换时间的算法;对于一个随机的数组比如是:arr=[2,4,1,2,5,3,4,8,7];
- 计算最该数组中的最大值和最小值o(n);
- 根据最大值和最小值设定计数数组的长度;
- 计数数组,表示各个数字出现的次数,将各个数字作为下标存入计数数组,对应的值为该数字出现的次数,比如c=[0,1,2,1,2,1,0,1,1];
- 累加数组,下标对应的元素的值表示小于等于该元素的数字的个数,比如对于上一步中c=[0,1,2,1,2,1,0,1,1],那么d=[0,1,3,4,6,7,7,8,9];计算方式就是第一个位置不变(因为小于等于该元素的只有他自己,他自己就是最小值),从第二个位置开始,每个下标(元素)的值等于上一个下标对应值加上自己的值;
- 分配,按照原始数组arr中的顺序,该元素对应的位置就是累加数组中当前元素下标的值-1就是排序后的该元素的数组下标,并且每分配一次,都将累加数组中对应下标元素的值减一;
/**
* 计数排序
*/
public class CounterSort {
//计数排序
public int[] counterSort(int[] arr){
int maxValue=selectMax(arr);
int minValue=selectMin(arr);
if(minValue<0){
//如果最小值小于零,使用偏移量将所有元素移动到0以上;偏移量为minValue的绝对值
for (int i=0;i<arr.length;i++) {
arr[i] += Math.abs(minValue);
}
}
//获取计数数组
int[] counterArray=counterArray(arr);
//直接获取累加数组
int[] accumulationArray = accumulationArray(counterArray);
//新数组
int[] newArray=new int[arr.length];
//进行分配
for (int i=0;i<arr.length;i++){
//计算下标
int index=accumulationArray[arr[i]]-1;
newArray[index]=arr[i];
//分配之后减一
accumulationArray[arr[i]]--;
}
return newArray;
}
//获得最大值
public int selectMax(int[] arr){
int maxValue=Integer.MIN_VALUE;
for(int i=0;i<arr.length;i++){
if(arr[i]>maxValue) maxValue=arr[i];
}
return maxValue;
}
//获得最小值
public int selectMin(int[] arr){
int minValue=Integer.MAX_VALUE;
for(int i=0;i<arr.length;i++){
if(arr[i]<minValue) minValue=arr[i];
}
return minValue;
}
//返回计数数组
public int[] counterArray(int[] arr){
int maxValue=selectMax(arr);
int[] counterArr=new int[maxValue+1];
for (int i=0;i<arr.length;i++){
counterArr[arr[i]]++;
}
return counterArr;
}
//返回累加数组
public int[] accumulationArray(int[] counterArray){
int[] accumulationArray=counterArray;
for (int i=1;i<counterArray.length;i++){
accumulationArray[i]+=accumulationArray[i-1];
}
return accumulationArray;
}
}
调试代码
public class CounterTest {
public static void main(String[] args) {
CounterSort counterSort=new CounterSort();
int[] arr={2,4,1,2,5,3,4,8,7};
int[] sort = counterSort.counterSort(arr);
System.out.println("排序后结果:"+ Arrays.toString(sort));
}
}
使用计数排序解决H指数的问题
代码同上,只需要把排序的部分改成自定义的计数排序就行了.