Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 毛虫和树叶。我们能比O(n*c)做得更好吗?_Algorithm_Math - Fatal编程技术网

Algorithm 毛虫和树叶。我们能比O(n*c)做得更好吗?

Algorithm 毛虫和树叶。我们能比O(n*c)做得更好吗?,algorithm,math,Algorithm,Math,在准备面试时发现此问题 假设一些毛虫从底部开始,跳到下一片叶子。他们 在跳到下一片之前先把叶子吃掉。我们得到了一个表示跳转步骤的数组 由毛毛虫制成。如果数组为[2,4,7],则表示毛虫[-0]将吃掉树叶2,4,6。。 毛虫[1]会吃树叶4,8,12。。毛虫会吃掉7,14,21…0代表地面。 计算未食用树叶的数量 让我们假设,如果当前叶子被吃掉,毛虫会跳到下一个目的地。这意味着,如果毛虫[7]发现树叶28被吃掉,它将继续吃掉树叶35 设c为毛虫的数量,n为树叶的数量 显而易见的蛮力解决方案是为每个

在准备面试时发现此问题

假设一些毛虫从底部开始,跳到下一片叶子。他们 在跳到下一片之前先把叶子吃掉。我们得到了一个表示跳转步骤的数组 由毛毛虫制成。如果数组为[2,4,7],则表示毛虫[-0]将吃掉树叶2,4,6。。 毛虫[1]会吃树叶4,8,12。。毛虫会吃掉7,14,21…0代表地面。 计算未食用树叶的数量

让我们假设,如果当前叶子被吃掉,毛虫会跳到下一个目的地。这意味着,如果毛虫[7]发现树叶28被吃掉,它将继续吃掉树叶35

设c为毛虫的数量,n为树叶的数量


显而易见的蛮力解决方案是为每个毛虫迭代大小为n的布尔数组,如果被吃掉,则将其标记为true,否则标记为false。它需要O(n*c)时间。我们能做得更好吗?

一只毛虫会吃掉它所有的“跳跃步”
j
,因此,如果它是单独的,那么每只毛虫都会吃掉地板(n/j)叶子

现在你必须弄清楚你数过几次的树叶。例如,如果计算第一条毛毛虫可除以2的所有叶子,则不必计算第二条毛毛虫的任何叶子,第二条毛毛虫跳4乘4

对于两个项目,计算两次的数字是两个项目的倍数,其中有
floor(n/lcm(j,j'))

请注意,对于三个术语,如果您进行此计算,可能会删除一些项两次:让我们在您的示例中取28。跳转步骤7时,毛虫会吃掉它,但其他两个都会被吃掉(因为28%4==28%2==0),因此您需要添加多次删除的倍数:
floor(n/lcm(j,j',j”)

你可以在这里看到一个模式,它是。一般公式如下:

假设Aj是一只毛虫用跳跃步骤j(如果它是单独的)吃掉的叶子。那么对于j一组多个捕捉器跳跃集,Aj是所有这些毛虫吃掉的叶子集

让我们也将集合的最小公倍数定义为集合中所有元素的最小公倍数,这样我们就可以编写
lcm(J)

包含排除公式中的[n]是考虑到的毛虫跳跃的集合,因此在你的例子中,
[2,4,7]
,我们迭代它的所有子集。
|J |
是子集的大小,| AJ |是J中每个毛虫可以吃的叶子的数量的大小,因此我们得到| AJ |=
地板(n/lcm(J))

现在您有了2c项*,因为这是
c
毛虫的子集数。请注意,通过保存最不常见的倍数,而不是从头开始重新计算,可以节省一些时间

我把编写实际代码作为“练习”,正如一些人喜欢说的那样:它基本上是在子集上迭代并计算最小公倍数,然后将其全部放在上面的总和中

这可以得到吃过的叶子的总数。从这里得到未吃过的叶子是很简单的


如果我们在一个小示例上进行此操作(以便能够进行检查),0位于地面,
1..24
树叶,而
[2,3,4]
caterpillar跳跃步骤

唯一幸存的叶子是{1,5,7,11,13,17,19,23}:去掉所有偶数和所有可除以3的数。也就是说,我们希望答案是8

  • 第一轮:大小为1的子集。
    • Caterpillar
      j=2
      一个人会吃掉24/2=12片树叶
    • 卡特彼勒
      j=3
      一个人会吃掉24/3=8片树叶
    • Caterpillar
      j=4
      一个人会吃掉24/4=6片树叶
  • 第二轮:大小为2的子集。
    • 毛虫
      j=2
      j=3
      都想吃24/6=4片叶子:{6,12,18,24}
    • 毛虫
      j=3
      j=4
      都想吃24/12=2片叶子:{12,24}
    • 卡特彼勒
      j=4
      j=2
      都想吃24/4=6片叶子:所有被
      4
      吃掉的叶子都是
      2
  • 第三轮:大小为3的子集:所有毛虫一起
    • 他们都想吃24/lcm(2,3,4)=24/12=2片叶子:{12,24}
  • 最后一轮:12+8+6-4-2-6+2=26-12+2=16片叶子被吃掉
因此,24-16=8片树叶仍然存在


*当然,这是最坏的情况。希望您将迭代大小不断增加的子集,并且只要子集J的最小公倍数大于
n
,您就可以忽略该J的所有超集。特别是,如果大小
k
的所有子集的lcm都大于n,则可以停止迭代

这是关于你提到的O(n*c)算法,如果你仔细看的话,就是O(n logc)


一只毛虫吃掉了它的“跳跃步”j的所有倍数,因此,如果它是单独的,那么每只毛虫都会吃掉地板(n/j)叶子

这种复杂性受到以下因素的限制:
n+n/2+n/3+…+n/c这只是对@cimbali建议的方法的优化。从包含caterpillar步幅的数组中。您可以从该数组中删除步幅值的倍数,以减少找到的组合数

例如,24叶和[2,3,4]毛虫跳跃步

  • 第一步: 穿过步幅阵列并移除2的倍数。因为4是2的倍数。从阵列中移除4

  • 第二步:大小为1的子集。 毛虫j=2只会吃掉24/2=12片叶子 毛虫j=3只会吃掉24/3=8片树叶

  • 第三步:大小为2的子集。 毛虫j=2和j=3都想吃24/6=4片叶子:{6,12,18,24}

所以24-16(12+8-4)=8片叶子仍然存在