Algorithm 快速确定数字是否除以集合中的任何元素

Algorithm 快速确定数字是否除以集合中的任何元素,algorithm,math,language-agnostic,Algorithm,Math,Language Agnostic,是否有一种算法可以快速确定一个数字是否是一组给定数字的一个因子 例如,12是[24,33,52]的一个因子,而5不是 有比线性搜索更好的方法吗?这个集合将包含几百万个元素。我不需要找到数字,只需要一个true或false结果。我认为在一般情况下,O(n)搜索就是你最终得到的结果。但是,根据一般数字的大小,假设集合已排序(您提到它可以排序),您可以通过观察以下情况大大加快搜索速度:如果您正在搜索一个可被D整除的数字,并且您当前已扫描x,且x不可被D整除,则下一个可能的候选对象显然在地板上([x+D

是否有一种算法可以快速确定一个数字是否是一组给定数字的一个因子

例如,
12
[24,33,52]
的一个因子,而
5
不是

有比线性搜索更好的方法吗?这个集合将包含几百万个元素。我不需要找到数字,只需要一个
true
false
结果。

我认为在一般情况下,O(n)搜索就是你最终得到的结果。但是,根据一般数字的大小,假设集合已排序(您提到它可以排序),您可以通过观察以下情况大大加快搜索速度:如果您正在搜索一个可被D整除的数字,并且您当前已扫描x,且x不可被D整除,则下一个可能的候选对象显然在地板上([x+D]/D)*D.也就是说,如果D=12,列表为

5 11 13 19 22 25 27
当您在13处扫描时,下一个可能的候选数字将是24。现在,根据输入的分布,您可以使用二进制搜索而不是线性搜索进行向前扫描,因为您正在搜索列表中不少于24的最小数字,并且列表已排序。如果D较大,则可能会保存大量比较就这样


然而,从纯计算复杂性的角度来看,排序和搜索将是O(n logn),而仅仅线性扫描是O(n).

如果根据常量列表检查大量数字,则加速该过程的一种可能方法是首先将列表中的数字分解为其素因子。然后将列表成员放入字典中,并将素因子作为键。然后当一个数字(潜在因子)出现时首先,将其分解为素数因子,然后使用构造的字典检查数字是否是可能是给定数字的倍数的数字的因子。

要针对常数集测试许多潜在因子,您应该认识到,如果集合中的一个元素只是其他两个元素的倍数s、 它是不相关的,可以删除。这种方法是一种古老算法的变体,称为测试大量候选项时运行时的.Trading启动时间:

  • 选择集合中大于1的最小数字
  • 从集合中删除该数字的任何倍数,,但其本身除外
  • 对于下一个最小的迭代次数重复2次。迭代次数将取决于与启动时间的权衡

  • 现在只剩下一个小得多的集合进行彻底的测试。为了提高效率,您需要为集合创建一个允许O(1)删除的数据结构,如链表,或者只替换“已删除”元素,然后将非零元素复制到一个新容器中。

    我不确定这个问题,所以让我问另一个问题:12是[6,33,52]的因子吗?很明显,12不除以6、33或52。但是12的因子是2*2*3,6、33和52的因子是2*2*2*3*3*11*13。12的所有因子都存在于集合中[6,33,52]具有足够的多重性,所以你可以说12是[6,33,52]的一个因子

    如果你说12不是[6,33,52]的因子,那么最好的解决方案就是测试每个数字是否可以被12整除;只需执行除法并检查余数。因此6%12=6,33%12=9,52%12=4,因此12不是[6.33.52]的因子。但是如果你说12是[6,33,52]的因子,然后,要确定数字f是否是集合ns的一个因子,只需将数字ns按顺序相乘,每次相乘后取余数模f,如果余数为0,则立即报告为真,如果到达数字ns列表末尾时余数不为0,则报告为假

    让我们举两个例子。首先,12是[6,33,52]的一个因子吗?第一个(平凡的)乘法得到6的余数,得到6的余数。现在6*33=198,除以12得到6的余数,我们继续。现在6*52=312和312/12=26r0,所以余数是0,结果是真的。第二,5是[24,33,52]的一个因子?乘法链为24%5=5,(5*33)%5=2,(2*52)%5=4,因此5不是[24,33,52]的因子


    该算法的一个变体最近被用于RSA密码系统;您可以了解攻击是如何工作的。

    由于要搜索的集合是固定的,所以组织集合进行搜索所花费的任何时间都将是很好的。如果您可以在内存中获取集合,那么我希望二叉树结构将非常适合。平均而言,搜索在二叉树中查找元素是一个
    O(logn)
    操作

    如果您有理由相信集合中的数字在整个范围内均匀分布
    [0..10^12]
    ,则对内存中已排序集合的二元搜索应该与搜索二元树一样进行。另一方面,如果集合中的中间元素(或集合的任何子集)如果不希望接近集合(或子集)所包含范围内的中间值,则我认为二叉树将具有更好的(实际)性能

    如果你不能将整个集合存储在内存中,那么将其分解成适合内存的块,并将这些块存储在磁盘上可能是一种方法。你可以将集合的根分支和上分支存储在内存中,并使用它们索引到磁盘上。保存在内存中的树部分的深度是你应该考虑的你自己决定吧,但是如果你需要的不仅仅是根和2级分支,在磁盘上有8个块,我会很惊讶

    当然,这只解决了问题的一部分,确定给定的数字是否在集合中;你真的想知道给定的数字是否是集合中任何数字的因子。正如我在评论中所建议的,我认为任何基于将集合中的数字分解的方法都是没有希望的,给出一个