Algorithm 毛虫和树叶。我们能比O(n*c)做得更好吗?
在准备面试时发现此问题 假设一些毛虫从底部开始,跳到下一片叶子。他们 在跳到下一片之前先把叶子吃掉。我们得到了一个表示跳转步骤的数组 由毛毛虫制成。如果数组为[2,4,7],则表示毛虫[-0]将吃掉树叶2,4,6。。 毛虫[1]会吃树叶4,8,12。。毛虫会吃掉7,14,21…0代表地面。 计算未食用树叶的数量 让我们假设,如果当前叶子被吃掉,毛虫会跳到下一个目的地。这意味着,如果毛虫[7]发现树叶28被吃掉,它将继续吃掉树叶35 设c为毛虫的数量,n为树叶的数量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为树叶的数量 显而易见的蛮力解决方案是为每个
显而易见的蛮力解决方案是为每个毛虫迭代大小为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
一个人会吃掉24/2=12片树叶j=2
- 卡特彼勒
一个人会吃掉24/3=8片树叶j=3
- Caterpillar
一个人会吃掉24/4=6片树叶j=4
- Caterpillar
- 第二轮:大小为2的子集。
- 毛虫
和j=2
都想吃24/6=4片叶子:{6,12,18,24}j=3
- 毛虫
和j=3
都想吃24/12=2片叶子:{12,24}j=4
- 卡特彼勒
和j=4
都想吃24/4=6片叶子:所有被j=2
吃掉的叶子都是4
2
- 毛虫
- 第三轮:大小为3的子集:所有毛虫一起
- 他们都想吃24/lcm(2,3,4)=24/12=2片叶子:{12,24}
- 最后一轮:12+8+6-4-2-6+2=26-12+2=16片叶子被吃掉
*当然,这是最坏的情况。希望您将迭代大小不断增加的子集,并且只要子集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}