「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
做完前面几道丑数题过来的,一下子就被坑了 这尼玛是重新定义了 丑数?
——leetcode此题热评
前言
大家好,我是一条,欢迎来到我的算法频道。
只做有趣的算法题,只为面试写算法。
Question
1201. 丑数 III
难度:中等
给你四个整数:n 、a 、b 、c ,请你设计一个算法来找出第 n 个丑数。
丑数是可以被 a 或 b 或 c 整除的 正整数 。
示例1 :
输入:n = 3, a = 2, b = 3, c = 5 输出:4 解释:丑数序列为 2, 3, 4, 5, 6, 8, 9, 10... 其中第 3 个是 4。
示例 2:
输入:n = 4, a = 2, b = 3, c = 4 输出:6 解释:丑数序列为 2, 3, 4, 6, 8, 9, 10, 12... 其中第 4 个是 6。
示例 3:
输入:n = 5, a = 2, b = 11, c = 13 输出:10 解释:丑数序列为 2, 4, 6, 8, 10, 11, 12, 13... 其中第 5 个是 10。
Solution
补充一个定理,容斥原理
容斥原理可以描述如下:
要计算几个集合并集的大小,我们要先将所有单个集合的大小计算出来,然后减去所有两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合相交的部分,依此类推,一直计算到所有集合相交的部分。
即一个区间的可以被a/b/c除的个数为 num/a+num/b+num/c (一位的) -num/(ab)-num(bc)-num(ac) (两位的)+num(abc) (三位的)
Code
/**
* @author 一条coding
*/
class Solution {
public int nthUglyNumber(int n, int a, int b, int c) {
long ans = 0;
long l = 0, r = (long) Math.min(a, Math.min(b, c)) * n;
long ab = this.lcm(a, b);
long ac = this.lcm(a, c);
long bc = this.lcm(b, c);
long abc = this.lcm(b, ac);
while (l <= r) {
long m = l + ((r - l) >> 1);
long N = m / a + m / b + m / c - m / ab - m / ac - m / bc + m / abc;
if (N < n) {
l = m + 1;
ans = l;
} else {
r = m - 1;
}
}
return (int) ans;
}
private long gcd(long a, long b) {
return b == 0 ? a : gcd(b, a % b);
}
private long lcm(long a, long b) {
return a * b / gcd(a, b);
}
}
最后
点赞,点赞,还TMD是点赞!