leetcode刷题(三)——容斥原理

12 篇文章 0 订阅
本文介绍了LeetCode中涉及到容斥原理的题目,讲解了如何利用容斥原理解决最大公约数、最小公倍数以及求解特定条件下的音乐播放列表数量等问题。通过实例解析算法思路,结合代码实现,帮助读者理解并掌握容斥原理在编程中的应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

leetcode刷题系列三。这一节的内容主要是容斥原理的题目和题解。

百度百科上容斥原理的解释:

在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理

公式
在这里插入图片描述

两个集合的容斥关系公式:A∪B =|A∪B| = |A|+|B| - |A∩B |(∩:重合的部分)
三个集合的容斥关系公式:|A∪B∪C|= |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|

例题
在这里插入图片描述
算法分析在这里插入图片描述

//求最大公约数
#define ll long long 
int gad(int a,int b)
{
	return b==0?a:gad(b,a%b);
}
//求最小公倍数
ll lcm(int a,int b)
{
	return a*b/gad(a,b);
}
int getabc(int n,int a,int b,int c)
{
	ll num1=lcm(a,b);
	ll num2=lcm(b,c);
	ll num3=lcm(a,c)
	ll ans=n/a+n/b+n/c-n/lcm(a,b)-n/lcm(a,c)-n/lcm(b,c)+n/lcm(num1,lcm(num2,num3));
	return ans;
}

在这里插入图片描述

题目一在这里插入图片描述

题目链接

#define ll long long
ll gcd(int a,int b)
{
    return b==0? a:gcd(b,a % b);
}

ll lcm(int a, int b)
{
    return a / gcd(a,b) * b;
}

int MIN(ll a, ll b)
{
    return a < b? a: b;
}

int nthUglyNumber(int n, int a, int b, int c)
{
    ll num1 = lcm(a,b);
    ll num2 = lcm(b,c);
    ll num3 = lcm(a,c);
    ll num0 = lcm(num1,lcm(num2,num3));
    int min = MIN(a,MIN(b,c));
    ll left = min;
    ll right = min * n;
    ll mid = 0;
    while(left < right)
    {
        mid = (left + right) / 2;
        int sum = mid / a + mid / b + mid / c - mid /num1 - mid / num2 -mid / num3 + mid / num0;
        if(sum >= n)
            right = mid;
        else if(sum < n)
            left = mid + 1 ;
    }
    return right; 

题目二在这里插入图片描述

题目链接

思路:考虑 dp[i][j]。最后一首歌,我们可以播放没有播放过的歌也可以是播放过的。如果未播放过的,那么就是 dp[i-1][j-1] * (N-j) 种选择方法。如果不是,那么就是选择之前的一首歌,dp[i-1][j] * max(j-K, 0)(j 首歌,最近的 K 首不可以播放)。

class Solution {
public:
    int numMusicPlaylists(int n, int len, int dis) {
        int mod=1e9+7;
        long dp[101][101];
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        //i为听过歌的数量
        //j为听了多少首歌
        //dis是歌曲间隔
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=len;j++)
            {
                dp[i][j]+=dp[i][j-1]*max(0,(i-dis));
                dp[i][j]+=dp[i-1][j-1]*(n-(i-1));
                dp[i][j]%=mod;
            }
        }
        return dp[n][len];
    }
};

在这里插入图片描述

总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 java开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。

由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的Gitee获取
还有 高级java全套视频教程 java进阶架构师 视频+资料+代码+面试题!

全方面的java进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值