Algorithm 检查号码是否为吸血鬼号码的最快方法?

Algorithm 检查号码是否为吸血鬼号码的最快方法?,algorithm,numbers,number-theory,Algorithm,Numbers,Number Theory,这里定义了一个吸血鬼号码。数字V是吸血鬼数字,如果: 它可以表示为X*Y,这样X和Y各有N/2位,其中N是V中的位数 X和Y都不应具有尾随零 X和Y的数字应与V的数字相同 我想出了一个解决办法 strV = sort(toString(V)) for factor <- pow(10, N/2) to sqrt(V) if factor divides V X <- factor Y <- V/factor if X

这里定义了一个吸血鬼号码。数字V是吸血鬼数字,如果:

  • 它可以表示为X*Y,这样X和Y各有N/2位,其中N是V中的位数
  • X和Y都不应具有尾随零
  • X和Y的数字应与V的数字相同
我想出了一个解决办法

strV = sort(toString(V))
for factor <- pow(10, N/2) to sqrt(V)
    if factor divides V
        X <- factor
        Y <- V/factor
        if X and Y have trailing zeros
           continue
        checkStr = sort(toString(X) + toString(Y))
        if checkStr equals strV return true
strV=sort(toString(V))

对于因子,以下是一些建议:

  • 首先是一个简单的改进:如果位数小于4或奇数,则返回false(或者如果v也是负值)

  • 您不需要排序
    v
    ,只需计算每个数字出现O(n)的次数即可

  • 您不必检查每个数字,只需检查数字的可能组合。这可以通过回溯来实现,并显著减少必须检查的数字量

  • 检查是否使用了所有数字的最终排序也不需要,只需将两个数字使用的数字相加,并与
    v
    中出现的数字进行比较即可

  • 下面是一个类似JS的语言的代码,它的整数永远不会溢出,
    V
    参数是一个不带前导0的整数字符串:

    编辑:事实证明,该代码不仅类似于JS,而且是有效的JS代码,因此可以确定1047527295416280确实是一个吸血鬼号码()

    var V,V,isVmp,数字,len;
    函数是吸血鬼(numberString){
    V=数字串;
    如果(V.length<4 | | V.length%2==1)
    返回false;
    v=parseInt(v);
    if(v<0)
    返回false;
    位数=计数位数(V);
    len=V.长度/2;
    isVmp=false;
    支票号码();
    返回isVmp;
    }
    函数计数位数{
    var offset=“0”。charCodeAt(0);
    var-ret=[0,0,0,0,0,0,0,0,0];
    对于(变量i=0;i0){
    数字[i]——;
    支票号码(i,len-1);
    数字[i]++;
    }
    }
    }否则如果(深度==0){
    如果(v%number==0){
    var b=v/数量;
    如果(数字%10!=0 | | b%10!=0){
    变量d=计数位数(“”+b);
    如果(d[0]==数字[0]&&d[1]==数字[1]&&d[2]==数字[2]&&
    d[3]==数字[3]&&d[4]==数字[4]&&d[5]==数字[5]&&
    d[6]==数字[6]&&d[7]==数字[7]&&d[8]==数字[8]&&
    d[9]==数字[9])
    isVmp=true;
    }
    }
    }否则{
    对于(变量i=0;i<10;i++){
    如果(数字[i]>0){
    数字[i]——;
    检查编号(编号*10+i,深度-1);
    数字[i]++;
    }
    }
    }
    }
    
    在伪代码中:

    if digitcount is odd return false
    if digitcount is 2 return false
    for A = each permutation of length digitcount/2 selected from all the digits,
      for B = each permutation of the remaining digits,
        if either A or B starts with a zero, continue
        if both A and B end in a zero, continue
        if A*B == the number, return true
    
    这里仍然可以执行许多优化,主要是确保每对可能的因素只尝试一次。换句话说,在选择排列时,如何最好地检查重复的数字

    但这就是我将使用的算法的要点


    附言:你不是在寻找素数,为什么要使用素数测试呢?你只关心这些是否是吸血鬼的数字;只有极少数可能的因素。无需检查sqrt(number)之前的所有数字。

    我在这里提出的算法不会检查所有的数字排列。它将尽可能快地消除可能性,这样实际上只会测试一小部分置换

    算法举例说明 下面是基于示例125460的工作原理。如果您可以直接阅读代码,则可以跳过此(长)部分:

    起初,这两种毒牙(即吸血鬼因素)显然不为人所知,问题可以表示为:

           ?**
       X   ?**
       -------
       =125460
    
    对于第一个因子的最左边的数字(标有
    ),我们可以选择数字0、1、2、5、4或6中的任何一个。但仔细分析,0是不可行的,因为产品的数字永远不会超过5位数。因此,对所有以零开头的数字进行排列是浪费时间的

    对于第二个因子的最左边的数字(也标有
    ),也是如此。但是,在查看组合时,我们可以再次筛选出一些不能帮助达到目标产品的对。例如,应放弃此组合:

           1**
       X   2**
       -------
       =125460
    
    使用这些数字可以获得的最大数字是199x299=59501(忽略我们甚至没有9的事实),这甚至不是所需数字的一半。因此,我们应该拒绝组合(1,2)。出于同样的原因,该对(1,5)可因采取这些位置而丢弃。类似地,对(4,5)、(4,6)和(5,6)也可以被拒绝,因为它们产生的乘积太大(>=200000)。我将把这种测试称为“范围测试”——确定目标数字是否在某个选定数字对的范围内

    在这一阶段,第一个和第二个方之间没有区别,因此我们也不必调查第二个数字小于第一个数字的对,因为它们反映了一个已经被调查(或拒绝)的对

    因此,在所有可能占据第一个位置的对中(有30种可能从一组6位数字中选取2位数字),只需调查以下4位:

    (1, 6), (2, 4), (2, 5), (2, 6)
    
    在更详细的表示法中,这意味着我们将搜索限制在以下数字模式:

           1**       2**       2**       2**
       X   6**   X   4**   X   5**   X   6**
       -------   -------   -------   -------
       =125460   =125460   =125460   =125460
    
           A         B         C         D
    
    很明显,在查看其他位置之前,这种可能性的减少大大减少了搜索树

    该算法将依次考虑这4种可能性,并为每种可能性检查下一个数字位置的可能性。因此,首先分析了配置A:

           1?*
       X   6?*
       -------
       =125460
    
    适用于 1?* X 6?* ------- =125460
    (0, 2), (0, 4), (0, 5)
    (2, 0), (2, 4), (2, 5)
    (4, 0), (4, 2), (4, 5)
    (5, 0), (5, 2), (5, 4)
    
           2?*
       X   4?*
       -------
       =125460
    
           2?*
       X   5?*
       -------
       =125460
    
           24*       24*       26*       26*
       X   50*   X   51*   X   50*   X   51*
       -------   -------   -------   -------
       =125460   =125460   =125460   =125460
    
           Ca        Cb        Cc        Cd
    
           246
       X   510
       -------
       =125460
    
     *-+-- (1, 6)
       |
       +-- (2, 4)
       |
       +-- (2, 5) -+-- (4, 0)
       |           |
       |           +-- (4, 1) ---- (6, 0) = success: 246 * 510
       /           /
       |           +-- (6, 0)
       |           |
       |           +-- (6, 1)
       |
       +-- (2, 6) ---- (0, 1) ---- (4, 5) = success: 204 * 615