原题
一个正整数如果能被 a
或 b
整除,那么它是神奇的。
给定三个整数 n
, a
, b
,返回第 n
个神奇的数字。因为答案可能很大,所以返回答案 对 10^9 7
取模 后的值。
示例 1:
代码语言:javascript复制
**输入:** n = 1, a = 2, b = 3
**输出:** 2
示例 2:
代码语言:javascript复制
**输入:** n = 4, a = 2, b = 3
**输出:** 6
提示:
1 <= n <= 10^9
2 <= a, b <= 4 * 10^4
难度Hard
标签数学
二分查找
分析
看完题目我感觉一个线性遍历就能出来了,可是忘记了今天这是一道困难题。于是乎我的第一个解法横空出世,默认的testCase也通过了。
代码语言:javascript复制func nthMagicalNumber(n int, a int, b int) int {
cnt := 0
maxVal := 1000000000 7
i := 1
for ; i < maxVal; i {
if i%a == 0 || i%b == 0 {
cnt
}
if cnt == n {
return i
}
}
return i
}
结果一提交就这样了。超时了 哈哈哈
于是开始重新分析题目,发现规律: 一个数里包含的神奇数字(x)的数量= x/a x/b - x/最小公倍数
代码实现
代码语言:javascript复制func nthMagicalNumber(n int, a int, b int) int {
start := min(a, b) // 开始的数从两数较小的数开始
end := n * min(a, b) // 结束的数 到 较小数 * n
gbs := minGongBeiShu(a, b)
maxVal := 1000000000 7
cnt := 0
for start <= end {
// 找到中间的数,计算出这个数 有几个神奇数字
mid := (start end) / 2
cnt = mid/a mid/b - mid/gbs
// 不断调整 左右两边的边界
if cnt >= n {
end = mid - 1
}
if cnt < n {
start = mid 1
}
// if cnt == n {
// break
// }
}
return (end 1) % maxVal
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func maxGongYueShu(a, b int) int {
for a != 0 {
a, b = b%a, a
}
return b
}
func minGongBeiShu(a, b int) int {
return a / maxGongYueShu(a, b) * b
}
力扣题库地址
https://leetcode-cn.com/problems/nth-magical-number
复杂度分析
- 时间复杂度: O(log(min(a,b) * n))
- 空间复杂度: O(1) 只用到了几个变量, start, end ,cnt等。