LeetCode 878. 第 N 个神奇数字
题目描述

题意分析
能被
a或b整除的正整数都是神奇数字,同时被两者整除也只算一个。将这些不同数字从小到大排列,求第n个,再对10^9 + 7取模返回。
解法:二分答案 + 容斥计数
核心思路
[!blue]
n可能很大,逐个生成神奇数字不合适。换一个方向:对候选数x,如果能快速知道不超过它的神奇数字有多少,就能判断第n个数字在它左侧还是右侧。不超过
x的a的倍数有x / a个,b的倍数有x / b个。两部分都包含最小公倍数lcm的倍数,直接相加会重复计数,因此由容斥得到count(x) = x / a + x / b - x / lcm,其中除法向下取整。随着
x增大,计数不会减少。于是答案就是第一个满足count(x) >= n的整数,可以二分这个真假分界。这个整数一定自身是神奇数字:否则从x - 1到x没有新增合法数,不可能恰好在这里首次达到n。搜索范围取
[1, n * min(a, b)]。较小因子的前n个倍数已经提供了n个不同神奇数字,所以右端一定不小于答案。若中点计数达到n,答案可能就是中点,也可能更小,令hi = mid;否则中点及左侧都不够,令lo = mid + 1。两端相遇时得到最小可行值。
解题步骤
- 用最大公约数计算最小公倍数。
- 在一到 n×min(a,b) 之间二分。
- 计数不少于 n 时保留左半区,否则排除中点及其左侧。
- 得到真实答案后再取模返回。
最小公倍数用
a / gcd(a, b) * b计算,边界、计数和乘法都使用宽整数。若a == b或一者整除另一者,容斥公式仍会自动去重,无需额外分支。取模只影响输出,不能提前用于二分中的大小比较。
代码实现
class Solution {
public int nthMagicalNumber(int n, int a, int b) {
long mod = 1_000_000_007L;
long g = gcd(a, b);
long l = (long) a / g * b;
long lo = 1;
// 前 n 个较小因子的倍数已经提供 n 个合法数,作为安全上界。
long hi = (long) n * Math.min(a, b);
while (lo < hi) {
long mid = lo + (hi - lo) / 2;
// 两个倍数集合相加后,减去最小公倍数对应的重复项。
long cnt = mid / a + mid / b - mid / l;
if (cnt >= n) {
hi = mid;
} else {
lo = mid + 1;
}
}
return (int) (lo % mod);
}
private long gcd(long x, long y) {
while (y != 0) {
long t = x % y;
x = y;
y = t;
}
return x;
}
}
func nthMagicalNumber(n int, a int, b int) int {
const mod int64 = 1_000_000_007
g := gcd(int64(a), int64(b))
l := int64(a) / g * int64(b)
lo := int64(1)
// 前 n 个较小因子的倍数已经提供 n 个合法数,作为安全上界。
hi := int64(n) * int64(min(a, b))
for lo < hi {
mid := lo + (hi-lo)/2
// 两个倍数集合相加后,减去最小公倍数对应的重复项。
cnt := mid/int64(a) + mid/int64(b) - mid/l
if cnt >= int64(n) {
hi = mid
} else {
lo = mid + 1
}
}
return int(lo % mod)
}
func gcd(x int64, y int64) int64 {
for y != 0 {
x, y = y, x%y
}
return x
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
复杂度分析
- 时间复杂度:$O(\log(n\min(a,b)+1))$,每轮常数次除法,最大公约数预处理在同阶上界内。
- 空间复杂度:$O(1)$。
关键点总结
[!green]
- 容斥负责去掉同时满足两个整除条件的重复数。
- 二分寻找首次达到,不是任意一个计数为 n 的位置。
- 上界乘法先提升为宽整数,比较过程中不取模。
易错点总结
[!yellow]
- 计数不减最小公倍数项:重复倍数被算两次。
- 乘法完成后才转宽类型:原类型中已经发生溢出。
- 二分过程中对数值取模:破坏大小关系和计数含义。
- 不可行时仍令左界等于 mid:相邻边界时可能无法收缩。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 1201. 丑数 III | 中等 | 本题判断能被a或b整除,原题扩展为三个除数,都可用容斥计数配合答案二分。 |
| 668. 乘法表中第k小的数 | 困难 | 同样无需生成全部候选,只要能统计不超过某值的候选数量就可定位第n项。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!