leetcode 878 第N个神奇的数字
题目描述
一个正整数如果能被 a 或 b 整除,那么它是神奇的
给定三个整数 n , a , b ,返回第 n 个神奇的数字。因为答案可能很大,所以返回答案 对 109 + 7 取模 后的值。
样例表示
输入:n = 1, a = 2, b = 3
输出:2
输入:n = 4, a = 2, b = 3
输出:6
数据范围
- 1 <= n <= 109
- 2 <= a, b <= 4 * 104
算法分析
- 思路1
使用是想的暴力去判断每个数是否符合神奇的数字,然后进行计数,得到最后的答案
因为数据量是4e13暴力回超时
class Solution {
public int nthMagicalNumber(int n, int a, int b) {
int nums = 1;
while(n > 0){
if(check(nums,a,b)){
nums++;
n--;
}else{
nums++;
}
}
return (nums - 1)%(1e9+7) ;
}
boolean check(int n , int a,int b){
boolean aa = false;
boolean bb = false;
if(n%a == 0){
aa = true;
}
if(n%b == 0){
bb = true;
}
return aa || bb;
}
}
- 思路2
因为神奇的数是被a或者b 进行整除,那我们可以将答案划分在下面的集合视图中
注意 lcm 是求最小公倍数 gcd 是求最大公倍数
int gcd(int a, int b){
return b == 0? a: gcd(b,a%b);
}
lcm = a * b/ gcd(a,b)
因为我们要求的答案是在1-N中 满足N/a + N/b - N / lcm (a,b) >= n的最小值
同时N和n 是满足单调递增的,所以可以使用二分答案的方法来快速的计算我们需要的最小值N
java代码
class Solution {
//容斥原理
//x 满足x/a + x/b -x/(lcm(a,b)) >= n
public int nthMagicalNumber(int n, int a, int b) {
long l = (long)1;
long r = (long)1e14;
while(l<r){
long mid = l+r >> 1;
if(mid/a + mid/b - mid/(a*b/gcd(a,b)) >= n){
r = mid;
}else{
l = mid+1;
}
}
return (int)(l % (1e9+7));
}
int gcd(int a, int b){
return b!=0? gcd(b,a%b):a;
}
}
python 代码
注意: python 中对数字的向下取整方法
class Solution:
def nthMagicalNumber(self, n: int, a: int, b: int) -> int:
l = 1
r = 1e14
while l < r:
mid = int((l+r)//2)
count = int(mid//a) + int(mid//b) - int(mid//(math.lcm(a,b)));
if count >= n:
r = mid
else:
l = mid + 1
return int(r % (1e9+7))
c++ 代码
class Solution {
const int mod = 1e9+7;
public:
int nthMagicalNumber(int n, int a, int b) {
long long l = 1;
long long r = 1e14;
while(l<r){
long long mid = l+r >> 1;
if(mid/a + mid/b - mid/(a*b/gcd(a,b)) >= n){
r = mid;
}else{
l = mid + 1;
}
}
return (int)(r % mod);
}
int gcd(int a,int b){
return b == 0? a : gcd(b, a%b);
}
};
d + 1;
}
}
return (int)(r % mod);
}
int gcd(int a,int b){
return b == 0? a : gcd(b, a%b);
}
};