878. 第 N 个神奇数字
一个正整数如果能被 a 或 b 整除,那么它是神奇的。
给定三个整数 n , a , b ,返回第 n 个神奇的数字。因为答案可能很大,所以返回答案 对 109 + 7 取模 后的值。
示例 1:
输入:n = 1, a = 2, b = 3 输出:2
示例 2:
输入:n = 4, a = 2, b = 3 输出:6
提示:
1 <= n <= 10^92 <= a, b <= 4 * 104
一看到这道题会想到264. 丑数 II - 力扣(LeetCode)的做法,用两个链表分别存a*1,a*2,a*3.....和b*1,b*2,b*3......,然后合并两个有序链表,顺带去重,最终链表的第n个元素就是结果,但是时间复杂度为O(N),n最大可取至10^9,所以肯定会超时,假定使用二分查找试试,时间复杂度为O(logN)。
为什么使用左侧边界的二分查找?
答:若n = 4, a = 2, b = 3,结果是6,6/2+6/3-6/6=4;
如果是7呢?7/2+7/3-7/6=4,也是4;
所以,选择最小的那个数,就是选择可以整除a或b的数,
这样的数除以a,b没有余数,理所当然是满足条件的数中最小的那个。
class Solution {
public:int gcd(int a,int b)//辗转相除法{int c=0;while(a%b!=0)//若a%b==0,则b就是最大公约数{c=a%b;a=b;//让b作ab=c;//让c作b}return b;}int nthMagicalNumber(int n, int a, int b) {int mod=1e9+7;int g=gcd(a,b);//a,b的最大公约数int lcm=(a*b)/g;//a,b的最小公倍数=(a*b)/最大公约数long right=min(a,b)*(long)n;//right是二分查找的上界,在[1,right]中至少有n个神奇数字long left=1;while(left<=right){long mid=left+(right-left)/2;//[1,mid]中能被a或b整除的数字的个数=能被a整除的个数+能被b整除的个数-能被能被a和b同时整除的个数int count=mid/a+mid/b-mid/lcm;if(count>=n)//左侧边界的二分查找,找到符合条件([1,mid]有n个神奇数字)的数中最小的那个{right=mid-1;}else{left=mid+1;}}return (right+1)%mod;}
};
上一篇:是js高级啊~