当前位置: 首页 > news >正文

leetcode刷题日记——H 指数

[ 题目描述 ]:
在这里插入图片描述
[ 思路 ]:

  • 题目给出一个作者的n篇论文各自的引用次数,要求求一个值h,h的意义是至少有 h 篇论文被引用次数大于等于 h,h是其中最大的值
  • 一个最简单的想法就是将h从1开始遍历,并记录
    • 当被引用次数大于h的总数大于h时,将h加1,重复这个操作
    • 当被引用次数大于h的总数大于h时,返回h
    • 当被引用次数大于h的总数小于h时间,返回h-1
  • 运行如下

在这里插入图片描述

int hIndex(int* citations, int citationsSize) {
    int h=1,sum=0;
    for(int i=0;i<citationsSize;i++){
        for(int j=0;j<citationsSize;j++){
            if(citations[j]>=h){
                sum++;
            }
        }
        if(sum>h){
            h++;
        }else if(sum==h){
            return h;
        }else{
            return h-1;
        }
        sum=0;
    }
    return h;
}

[ 优化 ]:

  • 时间复杂度O(n2),空间复杂度O(1)
  • 优先优化时间复杂度,由上面的做法来看,我们可以统计每个被引用的次数有多少篇论文,因为论文总数sum已知,所以被引用次数的情况最多只有sum次,然后遍历一次数组即可得出,但存储被引用次数的论文比较麻烦,如果用一维数组,那如果被引用次数很大的话,那么数组长度是未知的(题目给出是1000)
  • 或者二维数组,第一行存储被引用次数的种类,第二行存储该被引用次数的论文数量,但空间复杂度就变为O(2n)了
  • 换个思路,论文总数已知为n,那么h的最大值也就是n,那么,创建一个长度为n的数组sum记录每个h值情况下的被引用次数,数组下标+1为表示h,其值为大于等于该h值的个数;然后遍历citations数组,为下标小于citations[i]位置的值+1,最后遍历一遍sum,得出h;但这个思路的时间复杂度也为O(n2),空间复杂度为O(n),反而是增加了空间复杂度
int hIndex(int* citations, int citationsSize) {
    int* sum=(int*)malloc(citationsSize*sizeof(int));
    for(int i=0;i<citationsSize;i++){
        sum[i]=0;
    }
    for(int i=0;i<citationsSize;i++){
        for(int j=0;j<citationsSize;j++){
            if(citations[i]>=j+1) sum[j]++;
        }
    }
    for(int i=0;i<citationsSize;i++){
        if(sum[i]<i+1){
            return i;
        }
    }
    return citationsSize;
}
  • 沿着这种思想,为什么不能直接把citations数组的下标+1当作h值,然后我们对citations数组进行排序,然后遍历数组;
  • 先假设h值为1,那么被引用次数大于等于1的最少一次,如果是升序排列,则是最后一个数组元素大于等于1,为真则当前h值为1
  • 然后假设h值为2,如果升序排列,则倒数第二个元素大于等于2,为真,则当前h值为2,为假,则返回之前的h值
  • 运行如下

在这里插入图片描述

// 此处采用降序排序
int cmp(const void* a, const void* b) {
    return (*(int*)b) - (*(int*)a);
}

int hIndex(int* citations, int citationsSize) {
    qsort(citations, citationsSize, sizeof(int), cmp);
    for(int i=0;i<citationsSize;i++){
        if(citations[i]<i+1){
            return i;
        }
    }
    return citationsSize;
}
  • 时间复杂度O(nlogn),空间复杂度O(logn)

[ 官方题解 ]:

  • 一、排序,和上述相同,但官方给出的空间复杂度是O(logn),经查阅,在 C 标准库中,qsort 的实现通常是 O(log n) 的栈空间(因为采用优化后的快速排序,递归深度平均为 log n)。
  • 二、计数排序,新建并维护一个数组 counter 用来记录当前引用次数的论文有几篇,对于引用次数超过论文发表数的情况,我们可以将其按照总的论文发表数来计算即可。这样我们可以限制参与排序的数的大小为 [0,n],使得计数排序的时间复杂度降低到 O(n);从后向前遍历数组 counter,对于每个 0≤i≤n,在数组 counter 中得到大于或等于当前引用次数 i 的总论文数。
    • 标红处就是这个算法的关键思路,简直天才,死脑子想半天没想到这个点
    • 时间复杂度O(n),空间复杂度O(n)
int hIndex(int *citations, int citationsSize) {
    int n = citationsSize, tot = 0;
    int counter[n + 1];
    memset(counter, 0, sizeof(counter));
    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;
}
  • 方法三:二分搜索,设查找范围的初始左边界 left 为 0,初始右边界 right 为 n。每次在查找范围内取中点 mid,同时扫描整个数组,判断是否至少有 mid 个数大于 mid。如果有,说明要寻找的 h 在搜索区间的右边,反之则在左边。
int hIndex(int* citations, int citationsSize){
    int left=0,right=citationsSize;
    int mid=0,cnt=0;
    while(left<right){
        // +1 防止死循环
        mid=(left+right+1)>>1;
        cnt=0;
        for(int i=0;i<citationsSize;i++){
            if(citations[i]>=mid){
                cnt++;
            }
        }
        if(cnt>=mid){
            // 要找的答案在 [mid,right] 区间内
            left=mid;
        }else{
            // 要找的答案在 [0,mid) 区间内
            right=mid-1;
        }
    }
    return left;
}
http://www.dtcms.com/a/99232.html

相关文章:

  • 【Qt】数据库管理
  • Unity编辑器功能及拓展(3) —[Attribute]特性
  • 导航到渲染:浏览器加载页面的关键路径分析
  • 链表的创建:头插法与尾插法详解(数据结构)
  • 指纹识别之whois的作用:WHOIS数据在渗透测试中深度利用
  • vmware 创建win10 系统,虚拟机NAT网络设置
  • OJ题:移动零
  • Day 5
  • FPGA实现4K MIPI视频解码转HDMI2.0输出,基于IMX317摄像头,支持4K@60Hz,提供2套工程源码和技术支持
  • Logback 全面指南:从基础配置到高级应用
  • 76个复古黑白科幻几何抽象灵感运动元素纹理DJ舞台背景MV视频/PSD/PNG/JPG素材 Pixflow - Tour Visual Elements
  • 深入实践:基于WebSocket的全球化金融数据实时对接方案。 马来西亚、印度、美国金融数据API
  • 【Python桌面应用】PySide6 界面开发完全指南
  • javascript实现一个函数,将字符串中的指定子串全部替换为另一个字符串的原理,以及多种方法实现。
  • 1014 Waiting in Line
  • C++中shared_ptr 是线程安全的吗?
  • 使用 Avada 主题实现高级表单功能的技术指南
  • Day2 蓝桥杯省赛冲刺精炼刷题 —— 递归与递推
  • 浙江大学公开课|第二季|从大模型、智能体到复杂AI应用系统的构建——以产业大脑为例
  • final+模版设计模式的理解
  • [操作系统,学习记录]3.进程(2)
  • -PHP 应用文件上传函数缺陷条件竞争二次渲染黑白名单JS 绕过
  • AI大模型从0到1记录学习 day09
  • 求解AX=XB 方法
  • 车载软件刷写 --- 由擦除例程问题带来的反思
  • Java 图片压缩:高效压缩方案解析
  • 基于三维数字图像相关(DIC)技术的生物材料多尺度力学性能原位表征方法研究
  • 基于django优秀少儿图书推荐网(源码+lw+部署文档+讲解),源码可白嫖!
  • Centos安装Python3.7(亲测可用)
  • github——SSH连接配置文档