代码之家  ›  专栏  ›  技术社区  ›  Soham

将'n'个对象分布在'n'框中,这样任何框都不包含超过3个或'k'个对象

  •  0
  • Soham  · 技术社区  · 1 年前

    我正在考虑以下挑战:

    斐波那契是意大利比萨市的一位年轻居民。他花了很多时间参观比萨斜塔,这是该市的标志性建筑之一,位于他家附近。在他所有的塔楼之旅中,他在攀爬塔楼的大理石台阶时玩了一个奇怪的游戏。

    游戏:斐波那契喜欢一次爬一个台阶,一次爬两个台阶,或者一次爬三个台阶。这为原本单调的攀登任务增加了多样性。他想找到攀登n级台阶的总方法,假设他每级台阶的顺序很重要。你的任务是帮助斐波那契计算这个数字。

    例如,如果他想爬三级台阶,在n=3的情况下,他可以用四种不同的方法: (1,1,1):分三步做,一步一个脚印 (1,2):分两步走,先走一步,然后走两步 (2,1):分两步走,先走两步,然后走一步 (3) :只需一步,直接跳到第三步 再举一个例子,如果n=5,那么一些序列可能是: (1,3,1),(1,1,3),(3,1,1),(2,1,1,1),(1,2,1,1),(2,1,2) 每个序列都是攀登五级台阶的方法之一。

    这里要注意的是,序列的每个元素只能是1、2或3。 编写一个名为steps的递归函数,该函数接受正整数n作为参数。它应该返回斐波那契上升n步的方式总数。请注意,他的步骤顺序很重要。

    我假设逻辑与我们分布的简单组合学问题相同 n 无法区分的物体 n 可区分的盒子,使每个盒子最多容纳 k 对象,并找出每种组合的可能排列数量,从而得出标题。这是正确的看待方式,还是我采取了错误的方法?

    1 回复  |  直到 1 年前
        1
  •  2
  •   trincot Jakube    1 年前

    这是一个 Tribonacci sequence ,按顺序 A000073 ,跳过前两个零,因此从0开始,序列为1、1、2、4、7、13、24。。。等。

    一个简单的递归函数看起来像这样:

    function steps(n) {
        if (n < 2) return 1
        if (n == 2) return 2
        return steps(n-3) + steps(n-2) + steps(n-1)
    }
    

    如果真的实现为递归函数,你最好应用记忆化来确保它在线性时间内执行。

    请注意,这种递归实现的空间复杂度为O()。一种更节省内存的方法是不将其实现为递归函数,而是迭代实现,其空间复杂度为O(1):

    function steps(n) {
        a = 0
        b = 0
        c = 1
        while (n > 0) {
            d = a + b + c
            a = b
            b = c
            c = d
            n = n - 1
        }
        return c
    }
    

    这背后的逻辑

    首先,在楼梯的故事中,让我们称之为 楼梯的一部分,以及 移动 你爬楼梯的动作(在英语中,“step”一词可以同时用于这两个词,但这会让人很困惑)。

    在故事中,当你离顶部只有几步之遥(并且>2)时,你有三个下一步的选择:一步、两步或三步,以相同的幅度减少。如果对于这些选项中的每一个,你都知道有多少可能性可以继续达到顶峰,那么你可以把这三个数字加起来,得出当你离顶峰只有几步之遥时有多少可能性。

    所以我们有这个递归关系,其中 表示当你距离顶部仅几步之遥时的可能性数量:

    = 1. + 2. + 3.

    剩下的就是确定何时计数较小:

    0 1.
    1. 1.
    2. 2.

    第一个, 0 ,可能感觉不直观,但当你距离顶部0步时,你已经到达了顶部,不需要再移动了。然而,你 实现 目标,所以它算作1:显然有一种方法可以达到顶峰——什么都不做。

    有了这些规范,递归函数自然会随之而来。