[解题报告]《算法零基础100讲》(第29讲) 容斥原理

简介: [解题报告]《算法零基础100讲》(第29讲) 容斥原理

目录


零、写在前面


一、主要知识点


  1.容斥原理


二、课后习题


  509. 斐波那契数


  920. 播放列表的数量


  1782. 统计点对的数目


写在最后


零、写在前面


       今天是打卡的第29天,今天好累,不过这题的难度直接给我从困的状态泼醒了,这也太难了点吧,我足足肝了三个小时,太可怕了,知识点在:


《算法零基础100讲》(第29讲) 容斥原理https://blog.csdn.net/WhereIsHeroFrom/article/details/120875965

https://blog.csdn.net/WhereIsHeroFrom/article/details/120875965


一、主要知识点


  1.容斥原理


其实很简单的,就是多减的就加回来,多加的就减下去,就好了。


image.png



二、课后习题


509. 斐波那契数


1201. 丑数 III

https://leetcode-cn.com/problems/ugly-number-iii/


题目描述


给你四个整数:n 、a 、b 、c ,请你设计一个算法来找出第 n 个丑数。


丑数是可以被 a 或 b 或 c 整除的 正整数 。


思路


第n个丑数一定是满足下列式子的值 我们用二分去找到这个值就好了。。


int gcd(int a,int b){   //最大公约数
    if(a == 0)  return b ;
    return gcd(b%a,a);
}
long long gcm(long long a, long long b){    //最好输入就是长整型 不然会溢出哦
    return (a*b)/gcd(a,b);
}
bool check(int n,int a,int b,int c,long long mid){//判断是否满足
    if((mid/a+mid/b+mid/c-mid/gcm(a,b)-mid/gcm(a,c)-mid/gcm(b,c)+mid/gcm(gcm(a,b),c))>=n)   return true;
    return false;
}
int min(int a,int b){return a < b ? a : b;}//返回最小值
int nthUglyNumber(int n, int a, int b, int c){
    long long left = 0,right = n*min(min(a,b),c);
    while(left < right){        //二分查找满足条件的解
        int mid = left +(right - left)/2;
        if(check(n,a,b,c,mid))  right = mid;
        else left = mid+1;
    }
    return right;
}


920. 播放列表的数量


920. 播放列表的数量

https://leetcode-cn.com/problems/number-of-music-playlists/


题目描述


你的音乐播放器里有 N 首不同的歌,在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复)。请你为她按如下规则创建一个播放列表:


每首歌至少播放一次。

一首歌只有在其他 K 首歌播放完之后才能再次播放。

返回可以满足要求的播放列表的数量。由于答案可能非常大,请返回它模 10^9 + 7 的结果。


思路


考虑最后一首歌的情况,只有两种


一种是之前播放过  播放过那么就只能是之前的 j-k其中j表示之前的歌曲数目 但是不能小于0


一种是之前没播放过        没播放过的 那么可以选的有 n-j 种 其中j为之前播放过的数目


有递推式


int max(int a,int b){
    return a>b?a:b;
}
int numMusicPlaylists(int n, int goal, int k){
    int mod = 1000000007;
    long long ans[goal+1][n+1];
    memset(ans,0,sizeof(ans));
    ans[0][0] = 1;    //初始值
    for(int i = 1;i<=goal;i++)
        for(int j = 1;j<=n;j++){
            ans[i][j] = ans[i-1][j-1]*(n - j + 1) +ans[i-1][j]*max(j-k,0);//递推
            ans[i][j] %= mod;
        }
    return ans[goal][n]; 
}

1782. 统计点对的数目


1782. 统计点对的数目

https://leetcode-cn.com/problems/count-pairs-of-nodes/


题目描述


给你一个无向图,无向图由整数 n  ,表示图中节点的数目,和 edges 组成,其中 edges[i] = [ui, vi] 表示 ui 和 vi 之间有一条无向边。同时给你一个代表查询的整数数组 queries 。


第 j 个查询的答案是满足如下条件的点对 (a, b) 的数目:


a < b

cnt 是与 a 或者 b 相连的边的数目,且 cnt 严格大于 queries[j] 。

请你返回一个数组 answers ,其中 answers.length == queries.length 且 answers[j] 是第 j 个查询的答案。


请注意,图中可能会有 重复边 。


思路


最容易想到的方式就是记录所有的边信息,搞一个邻接矩阵,然后进行统计。但是 会超时。


为了加速,为了加速,一切都是为了加速。一开始会记录有哪些边,并且记录相应的权重。


接下来统计的时候


1.先统计任意两个顶点的边和大于所给值的 (这里的任意性才有加速的可能)


2.遍历所有边看其两个端点的和是否大于所给值的同时不符合要求 结果数量就要减少


其中为了计算两个顶点和大于给定值 用了双指针,就要预先对数据进行排序。这里复杂度大概就是 n+logn的快排复杂度。不过也同时增加了排序的空间消耗,需要对数据进行备份。排序之后所保存的hash映射就会丢失。


然后遍历所有边也就是m的复杂度。这道题卡时间太狠了。导致我一开始不能好好的初始化我的邻接矩阵,那我的思路就是,先遍历边 哪些边有值我再初始化哪些。


整道题的思路都是n^2的复杂度肯定比m的复杂度高,所有的一切全是围绕着遍历边进行复杂度的降低。

int cmp(int *a, int * b){
    return *a > *b;
}
int hash[400000001];    //邻接矩阵
int* countPairs(int n, int** edges, int edgesSize, int* edgesColSize, int* queries, int queriesSize, int* returnSize){
    if(queriesSize == 0)    {*returnSize = 0;return NULL;}
    *returnSize = queriesSize;
    int *ans = malloc(sizeof(int)*queriesSize);
    int stacke[edgesSize],stackesize = 0,hashp[n+1],hashsort[n+1];//边表 节点表
    memset(hashp,0,sizeof(hashp));memset(hashsort,0,sizeof(hashsort));
    for(int i = 0;i < edgesSize;i++){       //hash表的初始化!
        int temp;
        if(edges[i][0] > edges[i][1])   temp = edges[i][1]*n+edges[i][0]-1;
        else temp = edges[i][0]*n+edges[i][1] - 1;
        hash[temp]=0;
    }
    for(int i = 0;i < edgesSize;i++){   //利用hash表统计每条边的权重 加快速度
        int temp,j;
        hashp[edges[i][0]] ++;hashsort[edges[i][0]] ++;
        hashp[edges[i][1]] ++;hashsort[edges[i][1]] ++;
        if(edges[i][0] > edges[i][1])   temp = edges[i][1]*n+edges[i][0]-1;
        else temp = edges[i][0]*n+edges[i][1] - 1;
        if(!hash[temp]) stacke[stackesize++] = temp;
        hash[temp]++;
    }
    qsort(hashsort,sizeof(hashsort)/sizeof(int),sizeof(int),cmp);
    int anssize= 0;
    for(int i = 0;i < queriesSize;i++){
        int temp = 0,low = 1,high = n;//节点数字从1-n
        while(low < n){     //双指针求和为k的元素个数
            while(high > 1 && hashsort[low] + hashsort[high] > queries[i])
                high--;
            temp += (n - (low >high ?low:high));
            low++;
        }
        if(temp == 0)   {ans[anssize++] = 0;continue;}//提前继续 加速
        for(int k = 0;k < stackesize;k++){  //统计边的影响
            int p = stacke[k]/n,q = stacke[k]%n+1;
            if(hashp[p] + hashp[q] > queries[i] && hashp[p] + hashp[q] <= queries[i] + hash[stacke[k]])    temp--;
        }
        ans[anssize++] = temp;      //结果返回
    }
    return ans;
}



放个图庆祝一下过分么?


写在最后


多刷题,多刷题才知道怎么写,万人千题,集万人之势乘万人之事情,这过程中必然有很多人下车,希望在看我文章的各位,可以一起当最强的人!


相关文章
机器学习/深度学习 算法 自动驾驶
141 0
|
29天前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
122 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解
|
2月前
|
机器学习/深度学习 算法 文件存储
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
神经架构搜索(NAS)正被广泛应用于大模型及语言/视觉模型设计,如LangVision-LoRA-NAS、Jet-Nemotron等。本文回顾NAS核心技术,解析其自动化设计原理,探讨强化学习、进化算法与梯度方法的应用与差异,揭示NAS在大模型时代的潜力与挑战。
303 6
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
|
2月前
|
传感器 算法 定位技术
KF,EKF,IEKF 算法的基本原理并构建推导出四轮前驱自主移动机器人的运动学模型和观测模型(Matlab代码实现)
KF,EKF,IEKF 算法的基本原理并构建推导出四轮前驱自主移动机器人的运动学模型和观测模型(Matlab代码实现)
|
2月前
|
算法
离散粒子群算法(DPSO)的原理与MATLAB实现
离散粒子群算法(DPSO)的原理与MATLAB实现
90 0
|
3月前
|
机器学习/深度学习 人工智能 编解码
AI视觉新突破:多角度理解3D世界的算法原理全解析
多视角条件扩散算法通过多张图片输入生成高质量3D模型,克服了单图建模背面细节缺失的问题。该技术模拟人类多角度观察方式,结合跨视图注意力机制与一致性损失优化,大幅提升几何精度与纹理保真度,成为AI 3D生成的重要突破。
203 0
|
3月前
|
算法 区块链 数据安全/隐私保护
加密算法:深度解析Ed25519原理
在 Solana 开发过程中,我一直对 Ed25519 加密算法 如何生成公钥、签名以及验证签名的机制感到困惑。为了弄清这一点,我查阅了大量相关资料,终于对其流程有了更清晰的理解。在此记录实现过程,方便日后查阅。
179 1
|
4月前
|
消息中间件 存储 缓存
zk基础—1.一致性原理和算法
本文详细介绍了分布式系统的特点、理论及一致性算法。首先分析了分布式系统的五大特点:分布性、对等性、并发性、缺乏全局时钟和故障随时发生。接着探讨了分布式系统理论,包括CAP理论(一致性、可用性、分区容错性)和BASE理论(基本可用、软状态、最终一致性)。文中还深入讲解了两阶段提交(2PC)与三阶段提交(3PC)协议,以及Paxos算法的推导过程和核心思想,强调了其在ZooKeeper中的应用。最后简述了ZAB算法,指出其通过改编的两阶段提交协议确保节点间数据一致性,并在Leader故障时快速恢复服务。这些内容为理解分布式系统的设计与实现提供了全面的基础。
|
4月前
|
存储 算法 安全
Java中的对称加密算法的原理与实现
本文详细解析了Java中三种常用对称加密算法(AES、DES、3DES)的实现原理及应用。对称加密使用相同密钥进行加解密,适合数据安全传输与存储。AES作为现代标准,支持128/192/256位密钥,安全性高;DES采用56位密钥,现已不够安全;3DES通过三重加密增强安全性,但性能较低。文章提供了各算法的具体Java代码示例,便于快速上手实现加密解密操作,帮助用户根据需求选择合适的加密方案保护数据安全。
346 58

热门文章

最新文章