C++ 快速求两组数的公素数
我一直在努力解决这个问题: 我有它在返回正确答案方面的功能,但对于较大的数字来说,它的速度非常慢,我想看看是否有人能更好地更快地完成它,或者解释我可以优化它的方法C++ 快速求两组数的公素数,c++,math,optimization,primes,C++,Math,Optimization,Primes,我一直在努力解决这个问题: 我有它在返回正确答案方面的功能,但对于较大的数字来说,它的速度非常慢,我想看看是否有人能更好地更快地完成它,或者解释我可以优化它的方法 bool IsPrime(int number) { for (int i = 2; i < number; i++) { if (number % i == 0) { return false; } } return tr
bool IsPrime(int number)
{
for (int i = 2; i < number; i++)
{
if (number % i == 0)
{
return false;
}
}
return true;
}
bool GetPrimeFactors(int valueA, int valueB)
{
if(valueA < 0 || valueB < 0)
return false;
int max = sqrt(std::max(valueA, valueB)) + 1;//sqrt(std::max(valueA, valueB));
std::vector<int> factors;
bool oneSuccess = false;
for(int i = 2; i <= max; i++)
{
bool remainderA = valueA % i == 0;
bool remainderB = valueB % i == 0;
if(remainderA != remainderB)
return false;
if(IsPrime(i))
{
//bool remainderA = valueA % i == 0;
// bool remainderB = valueB % i == 0;
if(remainderA != remainderB )
{
return false;
}
else if(!oneSuccess && remainderA && remainderB)
{
oneSuccess = true;
}
}
}
return true;
}
int solution(vector<int> &A, vector<int> &B) {
int count = 0;
for(size_t i = 0; i < A.size(); i++)
{
int valA = A[i];
int valB = B[i];
if(GetPrimeFactors(valA, valB))
++count;
}
return count;
}
bool IsPrime(整数)
{
for(int i=2;i更新的):
bool IsPrime(整数)
{
如果(数字%2==0)
{
返回(数字=2);
}
整数极限=sqrt(数字);
对于(inti=3;i你实际上不需要找到数字的素数因子来决定它们是否有相同的素数因子
这是我想出的一个通用算法,用于检查a
和b
是否具有相同的素因子。这将比素因子分解a
和b
快得多
如果a==b
,答案是true
如果a==1 | | b==1
,则答案为false
用于查找2个数字的GCD。如果GCD==1
,则答案为false
请注意,GCD
需要包含两个数字的所有素数因子才能得到正确答案,因此请检查newa=a/GCD
和newb=b/GCD
是否可以通过重复将它们除以Euclid(newa,GCD)
和Euclid(newb,GCD)而减少为1
直到newa
和newb
到达1
哪个成功,或者Euclid(newa,GCD)
或者Euclid(newb,GCD)
返回1
哪个失败
让我们看看这对a=75,b=15是如何起作用的:
1) GCD=欧几里德(75,15)=15
2) newa=75/15=5,newb=15/15=1,用newb完成
3) 纽瓦=5/欧几里德(5,15)=5/5=1成功!
a=6,b=4怎么样:
1) GCD=欧几里德(6,4)=2
2) 新A=6/2=3,新B=4/2=2
3) 欧几里德(纽瓦,2)=欧几里德(3,2)=1失败!
a=2,b=16怎么样:
1) GCD=欧几里德(2,16)=2
2) newa=2/2=1(这很好),newb=16/2=8
3) 纽布=8/欧几里德(8,2)=8/2=4
4) 纽布=4/欧几里德(4,2)=4/2=2
5) newb=2/欧几里德(2,2)=2/2=1成功!
发现了非常详细的解释:
假设两个数N
和M
,用素数分解,然后将N
和M
的GCD表示为P1*P2*P3*P4*…Px
(每一个都是GCD(N,M)
)的素因子。然后,表示N/GCD(N,M)
和M/GCD(N,M)
分别用它们的素因子表示为N1*N2*N3*…Ny
和M1*M2*M3*…Mz
;然后,N
和M
可以表示如下
N = (P1 * P2 * P3 ... Px) * N1 * N2 * N3 * ... Ny
M = (P1 * P2 * P3 ... Px) * M1 * M2 * M3 * ... Mz
由于(P1*P2*P3…Px)
是gcd(N,M)
,因此N
和M
共有的任何素数因子总是在(P1,P2,P3,…Px)
中至少出现一次
换句话说,如果在(P1,P2,P3,…Px)
中找不到“N/gcd(N,M)
”(N1,N2,N3…Ny)
的任何素数因子,它就不是M
的素数因子。因此,可以说N
和M
的素数因子集并不完全相同
类似地,如果在(P1,P2.P3,…Px)
中找不到“M/gcd(A,B)
”(M1,M2,L3…Ly)
的任何素数因子,它就不是N
的素数因子,可以说N
和M
的素数因子集并不完全相同
因此,问题只是检查N1 Ny
和M1 Mz
中的任何一个是否从未出现在P1 Px
中
现在让我们考虑一下。让<代码> x= n/gCD(n,m)< /代码>,考虑<代码> gCD(gCD(n,m),x)< /c> > /p>
目前,情况如下
gcd(N,M): P1 * P2 * P3 ... Px
X : N1 * N2 * N3 ... Ny
如果gcd(N,M)%X==0
,那么X
的所有素因子都包含在gcd(N,M)
中
如果不是,那么我们计算gcd(gcd(N,M,X)
。如果这两个值的gcd只有1,这意味着N1 Ny
中没有一个出现在p1px
中;这意味着N
值有一个不与M
共享的素数因子
如果gcd大于1,那么我们计算X/gcd(gcd(N,M),X)
,并在下一轮更新X
。这意味着我们取出了X
的一些素数因子,构成gcd(gcd(N,M),X)
,并将其用于下一轮
如果此时gcd(N,M)%X==0
,这意味着X
的所有素数因子都包含在gcd(N,M)
中。如果没有,我们将重复上述操作。上述@vacawama解决方案的python实现
def gcd_division(a, b):
if not a%b:
return b
return gcd_division(b, a%b)
def prime_reduce(n, gcd):
na = n // gcd
ngcd = gcd_division(na, gcd)
if na == 1:
return True # success base case
elif ngcd == 1:
return False
return prime_reduce(na, ngcd)
def solution(A, B):
Z = len(A)
result = 0
for i in range(0, Z):
a, b = A[i], B[i]
if a == b:
result += 1
else:
gcd = gcd_division(a, b)
result += (prime_reduce(a, gcd) and prime_reduce(b, gcd))
return result
我使用以下测试用例运行它
if __name__ == '__main__':
test_cases = (
(1, ([15, 10, 9], [75, 30, 5]) ),
(2, ([7, 17, 5, 3], [7, 11, 5, 2]) ),
(2, ([3, 9, 20, 11], [9, 81, 5, 13]) ),
)
for expected, args in test_cases:
got = solution(*args)
print('result', expected, got)
assert(expected == got)
它的100%Java实现基于的答案:
class Solution {
public int solution(int[] A, int[] B) {
int count = 0;
for(int i = 0; i < A.length; i++){
if(A[i] == B[i]) count++;
else if(A[i] == 1 || B[i] == 1) continue;
else{
int GCD = gcd(A[i], B[i]);
if(GCD == 1) continue;
int newA = A[i]/GCD;
int newB = B[i]/GCD;
if(checkDiv(newA, GCD) && checkDiv(newB, GCD)) count++;
}
}
return count;
}
public boolean checkDiv(int num, int gcd){
if(num == 1) return true;
else if(gcd == 1) return false;
else {
gcd = gcd(gcd, num);
num = num/gcd;
return checkDiv(num, gcd);
}
}
public int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a % b);
}
}
类解决方案{
公共int解决方案(int[]A,int[]B){
整数计数=0;
for(int i=0;iif __name__ == '__main__':
test_cases = (
(1, ([15, 10, 9], [75, 30, 5]) ),
(2, ([7, 17, 5, 3], [7, 11, 5, 2]) ),
(2, ([3, 9, 20, 11], [9, 81, 5, 13]) ),
)
for expected, args in test_cases:
got = solution(*args)
print('result', expected, got)
assert(expected == got)
class Solution {
public int solution(int[] A, int[] B) {
int count = 0;
for(int i = 0; i < A.length; i++){
if(A[i] == B[i]) count++;
else if(A[i] == 1 || B[i] == 1) continue;
else{
int GCD = gcd(A[i], B[i]);
if(GCD == 1) continue;
int newA = A[i]/GCD;
int newB = B[i]/GCD;
if(checkDiv(newA, GCD) && checkDiv(newB, GCD)) count++;
}
}
return count;
}
public boolean checkDiv(int num, int gcd){
if(num == 1) return true;
else if(gcd == 1) return false;
else {
gcd = gcd(gcd, num);
num = num/gcd;
return checkDiv(num, gcd);
}
}
public int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a % b);
}
}
function solution(A, B) {
function getGcd(a,b, res = 1) {
if (a === b) return res * a;
if (a % 2 === 0 && b % 2 === 0) return getGcd(a/2, b/2, 2 * res);
if (a % 2 === 0) return getGcd(a/2, b, res);
if (b % 2 === 0) return getGcd(a, b/2, res);
if (a > b) return getGcd(a-b, b, res);
else return getGcd(a, b-a, res);
}
const hasCommonPrimeDivisors = (a, b) => {
if (a === b) return true;
if (a === 1 || b === 1) return false;
let gcd = getGcd(a, b);
if (gcd === 1) return false;
while (a !== 1 || b !== 1) {
let newGcd;
if (a !== 1) {
newGcd = getGcd(a, gcd);
if (newGcd === 1) {
return false;
}
a = a / newGcd;
}
if (b !== 1) {
newGcd = getGcd(b, gcd);
if (newGcd === 1) {
return false;
}
b = b/newGcd;
}
}
return true;
}
let count = 0
A.forEach((a, index) => {
const b = B[index];
if (hasCommonPrimeDivisors(a, b)) {
count++;
}
})
return count;
}