确定一个数字是否由其他两个数字相乘的算法

莫城堡A

可以说它是2k+2+3p=n作为测试给出的,在以下情况下,如何找出数字的测试为真对数字有效k>=0, p>=0, n>=0

example1:n = 24应该结果为true,因为k = 5&p = 4 => 2(5)+ 2 + 3(4)= 24

example2:n = 11应该结果为true,因为k = 0&p = 3 => 2(0)+ 2 + 3(3)= 11

example3:n = 15应为true,因为k = 5&p = 1 => 2(5)+ 2 + 3(1)= 15

我想知道是否有数学解决方案。我像下面这样解决了:

//let say 2k+2+3p=n
var accepted = false;
var betterNumber= n-2;
//assume p=0
var kReminder= (betterNumber)%2==0;
//assume k=0
var pReminder= (betterNumber)%3==0;

if (kReminder || pReminder){
    accepted=true;
}else{
    
    var biggerChunk= Math.Max(2,3); //max of 2k or 3p, here i try to find the bigger chunk of the 
    var smallerChunk= Math.Min(2,3);

    if ((betterNumber%bigger)%smallerChunk==0){
        accepted=true;
    }else
    {
        accepted=false;
    }    
}

仍然有一些我没有看到的案例。所以我想知道它是否有更好的解决方案。

更新资料

上面的测试只是一个例子。该解决方案应足够有效,适用于大数或数字的任意组合1000000k+37383993+37326328393p=747437446239902

SergGr

戴夫(Dave)已经给出了一个建设性的有效答案,但我想分享一些背后的数学知识。

一段时间以来,我将忽略该+ 2部分,因为它的意义不大,而将注意力集中在此问题的一般形式上:给定两个正整数,ab检查数字是否X可以表示为k*a + m*bwherekm是非负整数。扩展欧几里得算法本质上保证:

  1. 如果数字X不能被整除GCD(a,b),则不能将其表示为k*a + m*b整数km

  2. 如果numberX可被number整除GCD(a,b)并大于或等于a*b,则可以k*a + m*b用非负整数kand表示m这源于d = GCD(a,b)可以以这种形式表示的事实(我们称它为d = k0*a + m0*b)。如果那样的X = Y*dX = (Y*k0)*a + (Y*m0)*b如果这两个系数中的一个为负,则可以将另一个系数进行加法或减法,a*b换取所需的倍数X = (Y*k0 + b)*a + (Y*m0 - a)*b并且由于X >= a*b您始终可以通过这种方式使两个系数均为非负数。(注意:这显然不是找到合适的一对系数的最有效方法,但是由于您仅询问是否存在这样的系数就足够了。)

  3. 因此,唯一的灰色区域是范围内的X可被GCD(a,b)整除的数字(0, a*b)我不知道有关此区域的任何一般规则,但是您可以对其进行显式检查。

因此,您可以执行#3中所述的预计算,然后可以通过简单的比较+可能会针对范围的预计算布尔数组检查几乎立即回答此问题(0, a*b)

如果实际的问题是关于k*a + m*b + c形式,其中abc是固定的,很容易转换到k*a + m*b仅通过减去问题cX

更新(大值的ab

如果您的ab大,因此您无法(0, a*b)事先缓存该范围,那么我唯一的想法就是通过合理有效的算法按需检查该范围内的值。代码如下:

function egcd(a0, b0) {
    let a = a0;
    let b = b0;
    let ca = [1, 0];
    let cb = [0, 1];

    while ((a !== b) && (b !== 0)) {
        let r = a % b;
        let q = (a - r) / b;
        let cr = [ca[0] - q * cb[0], ca[1] - q * cb[1]];
        a = b;
        ca = cb;
        b = r;
        cb = cr;
    }

    return {
        gcd: a,
        coef: ca
    };
}

function check(a, b, x) {
    let eg = egcd(a, b);
    let gcd = eg.gcd;
    let c0 = eg.coef;

    if (x % gcd !== 0)
        return false;

    if (x >= a * b)
        return true;

    let c1a = c0[0] * x / gcd;
    let c1b = c0[1] * x / gcd;
    if (c1a < 0) {
        let fixMul = -Math.floor(c1a / (b / gcd));
        let c1bFixed = c1b - fixMul * (a / gcd);
        return c1bFixed >= 0;
    }
    else { //c1b < 0
        let fixMul = -Math.floor(c1b / (a / gcd));
        let c1aFixed = c1a - fixMul * (b / gcd);
        return c1aFixed >= 0;
    }
}

该代码背后的思想基于上面步骤2中描述的逻辑:

  1. 使用扩展的欧几里得算法计算GCD和Bézout系数(如果ab固定,则可以将其缓存,但即使这样也不算很快)。
  2. 从上面检查条件#1(绝对不是)和#2(绝对是)
  3. 对于(0, a*b)范围内的值,只需将Bézout系数乘以即可确定一些系数X/gcdF
  4. 找出两者中的哪一个为负数,并找到最小乘数以通过将一个系数换成另一个系数来固定它。
  5. 将此乘数应用于其他(最初为正)系数,并检查其是否仍为正。

该算法的工作,因为所有可能的解决方案X = k*a + m*b可以从一些基本的解决方案来获得(k0, m0)使用的(k0 + n*b/gcd, m0 + n*a/gcd)一些整数n因此,要找出是否有与这两个解决方案k >= 0m >= 0所有你需要的是找到与最小正解k,并检查m它。

该算法的复杂性由对数的扩展欧几里得算法决定。如果可以缓存,则其他所有内容都是固定时间。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

定期写一个反向链接以确定两个数字是否相等

检查一个数字是否是另外两个数字的和

确定一个数字数组是否可以分为两个数组,每个数组保存相同的数字总和

Bash 函数将确保一个数字 (n) 可以被其他两个数字 (x) 和 (y) 整除

有没有更好的方法来检查一个数字是否是两个数字的范围

如何对一个数字的数字求和,然后检查它是否存在于其他数字中

python:总结一个列表的两个数字

检查一个数字是否是两个质数的和

检查一个数字是否被其他平均数除

从两个数字中随机选择一个数字

如何检查值是否在一个单元格中的两个数字之间

验证两个数字之间是否包含一个值

如何确定一个数字是否在另一个数字的某个范围内

时间,这是否一个数的函数的复杂性是两个数字的力量

数组中的差/和,以检查生成的两个数字是否导致另一个数组

判断一个数是否与数组中的任意其他两个数组成一个连续的三个数

检查两个数字是否可以相同的算法

下一个数字相乘

如何排列一个数字的数字,以便当我将它分成两个相等数字的数字时,这两个数字的乘积是最大的?

如何将两个数字相乘并获得每两个数字相乘的SUM?

两个数相乘的算法

确定一个数字是否包含用于课堂分配的数字

确定一个数字是否可以用预选的数字和时间组成

如何用 selenium 和 java 比较两个数字?(一个数字来自 CSV 文件,另一个数字来自网站)

是否有一个numpy样式将两个数组元素相乘?

显示两个区间之间的数字的 C++ 程序检查一个数字是否可以表示为两个质数之和

在python中将一个数组与其他两个数组进行比较

对一个数组进行排序并使其他两个数组保持同步

返回一个数组的函数,该数组是其他两个数组的交集