计算梯子上可能路径的数量

时间:2012-09-03 23:51:50

标签: java algorithm fibonacci

我似乎无法想出一个算法来解决以下问题,我尝试使用一系列for循环,但它变得太复杂了:

  

梯子有n个阶梯,人们可以使用任何一个爬梯子   步骤1或步骤2的组合。有多少种可能的方法   还有一个人爬上梯子?

例如,如果梯子有 3步,这些将是可能的路径:

  • 1-1-1
  • 2-1
  • 1-2

4步

  • 1-1-1-1
  • 2-1-1
  • 1-2-1
  • 1-1-2
  • 2-2

对于如何做到这一点的任何见解将不胜感激。另外,我在Java工作。

编辑:我确实会使用较小的n值,但知道如何管理较大的值肯定会很好。

6 个答案:

答案 0 :(得分:28)

有趣的是,这个问题有一个简单的解决方案。你可以使用递归:

public static int countPossibilities(int n) {
    if (n == 1 || n == 2) return n;
    return countPossibilities(n - 1) + countPossibilities(n - 2);
}

每当你遇到这种“棘手”的问题时,请记住解决方案通常非常优雅,并且总是检查是否可以通过递归来完成。

编辑:我假设你会在这个问题中处理相对较小的n值,但是如果你处理大问题,那么上面的方法可能需要大量的时间到了。一种解决方案是使用将Map映射到n的{​​{1}} - 这样,就不会浪费时间进行已经完成的计算。像这样:

countPossibilities(n)

使用private static Map<Integer, Integer> map = new HashMap<Integer, Integer>(); static { map.put(1, 1); map.put(2, 2); } public static int countPossibilities(int n) { if (map.containsKey(n)) return map.get(n); int a, b; if (map.containsKey(n - 1)) a = map.get(n - 1); else { a = countPossibilities(n - 1); map.put(n - 1, a); } if (map.containsKey(n - 2)) b = map.get(n - 2); else { b = countPossibilities(n - 2); map.put(n - 2, b); } return a + b; } 尝试此操作。第二种方法比第一种方法快几个数量级。

答案 1 :(得分:7)

这实际上与Fibonacci sequence密切相关,正如目前为止的评论中仅简要提及的那样:每个步骤n都可以通过以下两个步骤({{1} })或下面的一步(n-2),因此达到该步骤的可能性的数量是达到其他两个步骤的可能性的总和。最后,只有一种可能性到达第一步(和第二步,即停留在地面上)。

此外,由于步骤n-1的可能性数量仅取决于步骤nn-1的结果,因此无需将所有这些中间值存储在地图中或在数组中 - 最后两个就足够了!

n-2

这不仅可以通过良好的共享减少代码量,而且还可以及时提供 O(n)的复杂性,并在空间中提供 O(1),存储所有中间值时, O(n)时间空间。

但是,即使public static long possForStep(int n) { // current and last value, initially for n = 0 and n = 1 long cur = 1, last = 1; for (int i = 1; i < n; i++) { // for each step, add the last two values and update cur and last long tmp = cur; cur = cur + last; last = tmp; } return cur; } 类型在long接近100时也会快速溢出, O(n)的空间复杂性并不是真正的问题,所以你可以同样也可以使用这个更容易阅读的解决方案。

n

更新:请注意,这与Fibonacci序列接近但不完全相同,后者从public static long possForStep(int n) { long[] values = new long[n+1]; for (int i = 0; i <= n; i++) { // 1 for n==0 and n==1, else values[i-1] + values[i-2]; values[i] = (i <= 1) ? 1 : values[i-1] + values[i-2]; } return values[n]; } 开始0, 1, 1, 2, 3,...,即1, 1, 2, 3, 5, ...,{{1} }}

答案 2 :(得分:1)

我会使用动态编程,每次解决梯子1档或2档较短的问题。

def solveLadder(numOfRungs):
  if numOfRungs<=2:
    return numOfRungs
  return solveLadder(numOfRungs-1)+solveLadder(numOfRungs-2)

答案 3 :(得分:0)

这是一个递归的树。您可能需要回溯那些无法工作的情况(例如,3阶梯的2-2)。

答案 4 :(得分:0)

这是斐波那契系列。您可以使用尾递归递归来优雅地解决它:

    let ladder n =
        let rec aux n1 n2 n =
            if n=0 then (n1 + n2)
            else aux n2 (n1+n2) (n-1)
        aux 1 1 (n-2)

更容易理解的非尾递归代码是:

    let rec ladder n =
        if n<=2 then n
        else ladder (n-1) + ladder (n-2)

您可以轻松将其翻译为Java。

答案 5 :(得分:-2)

  1. 列表项
  2. 如果我们可以采取的步骤是1或2,这是简单的斐波那契系列 为了

    • 楼梯可能情况

      1 ------------------ 1

      2 ------------------ 2

      3 ------------------ 3

      4 ------------------ 5

      5 ------------------ 8

      6 ------------------ 13

    等等