力扣刷题笔记 275. H 指数 II
1、问题描述
给定一位研究者论文被引用次数的数组(被引用次数是非负整数),数组已经按照 升序排列 。编写一个方法,计算出研究者的 h 指数。
h 指数的定义: “h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。(其余的 N - h 篇论文每篇被引用次数不多于 h 次。)"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/h-index-ii
2、示例
说明:
如果 h 有多有种可能的值 ,h 指数是其中最大的那个。
3、问题分析和解答
在输入接口中,依照题意无论提供的是数组还是vector,元素都是升序排列的,即这个序列是一个有序表。此外对于数组也额外提供了数组的大小。
耐心读题,我们知道要得到h的值,需要在有序表中对数据进行比较。
那么有序表的搜寻的算法要么按顺序暴力搜索要么二分查找;
3.1 暴力求解
对于暴力搜索这个问题会有两种搜寻方案:
-
从后往前遍历vector/array
若有Vector中的升序元素A={0,1,2,3,4,5}和待比较集合U={0,1,2,3,4,5}
由于是从后往前遍历vector那么需要做的就是按照题意,将vector中的元素倒序与U集合中的元素逐个比较,如5和0比较,4和1比较,一直比较下去我们会得到当A中元素为2时,此时2∈vector < 3∈U。由于vector升序,再往A的前面比较就没有意义了,所以h=3。
-
从前往后遍历vector/array
若有vector中的升序元素A={0,1,2,3,4,5}和待比较集合U={5,4,3,2,1,0}
由于从后往前遍历vector那么需要做的也是将vector中的元素顺序与U集合中的元素逐个比较,如0和5比较,1和4比较,2和3比较,最后3和2比较,3>2,那么h = 3。
前后遍历都是一样的,这里给出从后往前遍历的程序:
class Solution {
public:
int hIndex(vector<int>& citations) {
int h = 0;
for(int i = citations.size(); i > 0; i--){
int last = citations.at(i-1);
if(last > h){
h++;
continue;
}
break;
}
return h;
}
};
提交结果如下:
3.2 二分求解
对于二分查找,我们需要找出一个元素的下标mid,从mid到vector序列末的文章个数记作PCout。记len = vector.size()
,并且初始化right = len - 1, left = 0
- 若有
vector.at(mid)>=PCount
,那么我们可以尝试让h值更大些,即调整让mid往左一些,调整右边边界right = mid -1 - 若有
vector.at(mid)<PCount
,那么我们尝试让h值变小使之满足h值的定义,即调整让mid往右一些,调整左边边界left = mid + 1
然后确定下一次的mid。
直到不满足二分的条件:left<=right
为止。
程序如下:
class Solution {
public:
int hIndex(vector<int>& citations) {
int len = citations.size();
int left = 0, right = len - 1; //定义左边边界和右边边界
while(left <= right){
int mid = left +(right - left) / 2;
if(citations.at(mid) >= len - mid){ //这里的mid是下标,所以直接相减就可以得到个数
right = mid - 1;
}
else{
left = mid + 1;
}
}
return len - left;
}
};
运行结果:
需要指出的是二分解法不一定比暴力求解来得更快,取决于样例的数值。