【问题标题】:Find ways to get to a number of levels找到达到多个级别的方法
【发布时间】:2020-07-30 17:36:05
【问题描述】:

我在 CoderByte 上遇到了这个问题。要求是找到多种方法。我在 StackOverflow 和其他网站上找到了解决方案。但是继续前进,我还需要所有可能的方法来达到第 N 步。

问题描述:有N个台阶的楼梯,一次可以爬1或2个台阶。您需要计算并返回爬楼梯的独特方式的总数。采取的步骤顺序很重要。

例如,

输入:N = 3

输出:3

说明:爬 3 级楼梯有 3 种独特的方式:{1,1,1}、{2,1} 和 {1,2}

注意:在另一种情况下,一个人一次可以采取 2 或 3 或 4 个步骤(我知道这实际上是不可能的,但尝试为代码中的输入步骤添加可伸缩性)

我无法找到正确的逻辑来获得所有可能的方法。如果我在 Python 中获得解决方案会很有用,但这并不是严格的要求。

【问题讨论】:

    标签: python python-3.x algorithm loops logic


    【解决方案1】:

    这是使用itertools 库的最小解决方案:

    from itertools import permutations, chain
    
    solve = lambda n: [(1,)*n] + list(set(chain(*[permutations((2,)*i + (1,)*(n-2*i)) for i in range(1, n//2+1)])))
    

    对于您的示例输入:

    > solve(3)
    [(1, 1, 1), (1, 2), (2, 1)]
    

    它是如何工作的?

    如果我们向后退一步,就会更容易看到正在发生的事情:

    def solve(n):
        combinations = [(1,)*n]
        for i in range(1, n//2+1):
            combinations.extend(permutations((2,)*i + (1,)*(n-2*i)))
        return list(set(combinations))
    

    最微不足道的情况是您一次迈出一步,所以 n 步骤:(1,)*n。然后我们可以看看我们最多可以走多少双步,这是 n 除以 2 的底数:n//2。然后我们迭代可能的双步:尝试在每次迭代(2,)*i 时添加一个双步,用单步填充剩余空间(1,)*(n-2*i)

    来自 itertools 的函数 permutations 将为该迭代生成所有可能的单步和双步排列。输入 (1,1,2),它将生成 (1,1,2)、(1,2,1) 和 (2,1,1)。最后,我们使用将结果转换为set 的技巧来删除重复项,然后将其转换回列表。


    任何数量和长度的步骤的泛化(不是最优的!)

    一个班轮:

    from itertools import permutations, chain, combinations_with_replacement
    
    solve = lambda n, steps: list(set(chain(*[permutations(sequence) for sequence in chain(*[combinations_with_replacement(steps, r) for r in range(n//min(steps)+1)]) if sum(sequence) == n])))
    

    示例输出:

    > solve(8, [2,3])
    [(3, 2, 3), (2, 3, 3), (2, 2, 2, 2), (3, 3, 2)]
    

    更易于阅读的版本:

    def solve(n, steps):
        result = []
        for sequence_length in range(n//min(steps)+1):
            sequences = combinations_with_replacement(steps, sequence_length)
            for sequence in sequences:
                if sum(sequence) == n:
                    result.extend(permutations(sequence))
        return list(set(result))
    

    【讨论】:

    • 谢谢,@stjernaluiht。这是一个简化的解决方案,效果很好。我想知道如果用例更改为一次爬 2 或 3 步而不是 1 或 2 步会怎样。然后,当 n 是代码中的奇数时,一次 2 步的默认情况可能不起作用。请分享您的想法。
    • 很高兴它对你有用!这个问题对于任意步数的推广实际上是一个NP-hard问题,具体来说是subset sum problem的一个变体。这意味着直到找到解决方案的时间随着输入的大小呈指数增长。
    • 我在答案中添加了适用于任意数量和长度的步骤的概括,但这远非最佳解决方案。
    • 是的,这适用于所有输入案例。谢谢你快速的回复。真的很感激。
    【解决方案2】:
    def solve(n) :
        if (n == 0):
            return [[]]
        else:
            left_results = []
            right_results = []
    
            if (n > 0):
                left_results = solve(n - 1)
                for res in left_results: # Add the current step to every result
                    res.append(1)
    
            if (n > 1):
                right_results = solve(n - 2)
                for res in right_results: # Same above
                    res.append(2)
    
            return left_results + right_results
    

    我认为使用动态编程有更好的方法来做到这一点,但我不知道该怎么做。无论如何,希望它有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多