不要理解为什么这个C ++递归函数有效的逻辑

时间:2014-04-23 16:21:52

标签: c++ recursion

此功能用于生成楼梯上的大步和短步的组合数(由用户给出的值)。一个短步骤涉及一个步骤,一个大步幅涉及两个步骤。

但是,我不理解这里使用的递归洞察力。我真的很感激为什么会产生所需组合的数量。通过它,我可以看到它的工作原理,但我不确定自己将如何达到这个逻辑。

有人可以对此有所了解吗?

以下是代码:

int CountWays(int numStairs);
int combination_strides = 0;
const int LARGE_STEP = 2;
const int SMALL_STEP = 1;

int main() {

    cout << "Enter the number of stairs you wish to climb: ";
    int response = GetInteger();
    int combinations = CountWays(response);
    cout << "The number of stride combinations is: " << combinations << endl;

    return 0;
}


int CountWays(int numStairs) {

    if (numStairs < 4) {
    return numStairs;

    } else {
    return CountWays(numStairs - SMALL_STEP) + CountWays(numStairs - LARGE_STEP);

    }
}

6 个答案:

答案 0 :(得分:6)

要关注numStairs,您可以:

  • 迈出一小步,然后往下走(numStairs - SMALL_STEP);或
  • 迈出一大步,然后往下走(numStairs - LARGE_STEP)

因此,总路数是下降(numStairs - SMALL_STEP)的方式数和(numStairs - LARGE_STEP)下降方式的总和,因此递归。

很简单,看到有一种方法可以向下一步(S),两种向下运行两步(SS或L),三种向下运行三步(SSS,SL或LS),因此终止条件。

您可能会将此递归视为Fibonacci sequence的定义。对于奖励积分,您可能希望重新计算计算,使其以线性而非指数时间运行。

答案 1 :(得分:1)

好吧让我们这样想吧。我左边有一些楼梯。如果numStars&lt; 4,比组合的数量总是数字:

ss=small step (1)
ls=large step (2)
1 step-{{ss}}==1
2 steps-{{ss,ss},{ls}}==2
3 steps-{{ss,ss,ss},{ls,ss},{ss,ls}}==3

比这更大,它可能会变得更复杂。但如果我离开了,我可以采取一大步或一小步。如果我迈出了一大步,那么将会有numStars-LARGE_STEP步骤,所以我只需要找到这么多步骤的组合总数。如果我迈出一小步,我只需要找到numStais-SMALL_STEP的组合总数。

加入递归项,组合[n] =组合[n-1] +组合[n-2]。

应该注意的是,这不是以任何方式执行此操作的最快方法。这为每次迭代重做了大量的工作。动态编程方法更为可取。

int* num_combinations = new int[num_stairs];
for (int i = 0; i < 4; i++) num_combinations[i]=i;
for (int i = 4; i < num_stairs; i++) num_combinations[i]=num_combinations[i-1]+num_combinations[i-2];
int ret = num_combinations[num_stairs-1]+num_combinations[num_stairs-2]
delete[] num_conbinations;
return ret;

O(n) vs O(n ^ 2)

答案 2 :(得分:1)

在这种情况下,这是递归逻辑:

假设您N步骤编号为1N

在任何时候,您都可以选择以下两个选项之一:

  1. 爬一步
  2. 爬上两个步骤
  3. 你想计算爬上楼梯的不同组合的数量。

    现在,假设您目前正站在K步。

    您可以选择攀登步骤K+1或步骤K+2

    所以你需要做的就是添加:

    • 从步骤K+1升级到步骤N
    • 的不同组合的数量
    • 从步骤K+2升级到步骤N
    • 的不同组合的数量

    或者等效地,您可以添加:

    • 从楼梯底部爬到步骤N-(K+1)
    • 的不同组合的数量
    • 从楼梯底部爬到步骤N-(K+2)
    • 的不同组合的数量

    话虽如此,这是递归函数的工作原理:

    int CountWays(int numStairs)
    {
        if (numStairs < 4)
            return numStairs;
        // If there is  1 step , then there is  1 combination  to climb it   up
        // If there are 2 steps, then there are 2 combinations to climb them up
        // If there are 3 steps, then there are 3 combinations to climb them up
    
        int x = CountWays(numStairs - SMALL_STEP);
        // The number of different combinations to climb up
        // from the bottom of the staircase to step N-(K+1)
    
        int y = CountWays(numStairs - LARGE_STEP);
        // The number of different combinations to climb up
        // from the bottom of the staircase to step N-(K+2)
    
        return x+y;
    }
    

    你可能已经注意到这个函数只是产生 Fibonacci序列 1,2,3,5,8,13 ......

    BTW,在这种情况下,迭代实现会更有效率(与许多其他情况一样):

    int CountWays(int numStairs)
    {
        int prev = 0;
        int curr = 1;
        for (int i=0; i<numStairs; i++)
        {
            int next = prev+curr;
            prev = curr;
            curr = next;
        }
        return prev;
    }
    

答案 3 :(得分:0)

代码尝试通过在每个步骤中缩小问题来分解问题。 如果步骤少于四个,则可能的组合数量等于楼梯数:
- 对于一个楼梯,唯一可能的组合是一小步 - 对于两个楼梯,可能的组合是一大步或两个小步骤 - 对于三个楼梯,你可以走三个小台阶,一个小台阶,一个大台阶或一个大台阶和一个小台阶 这些案例将结束递归 对于其他每一个楼梯,你可以走一小步,然后走楼梯,或者一大步,然后是其他楼梯。 &#34;其余的楼梯&#34;是递归发生的地方:它只计算减少楼梯数的可能性数量(减少一到两步,取决于第一步的大小)。
将它们全部加在一起,就可以得到走上楼梯的组合总数。

答案 4 :(得分:0)

  

让f(n)为从开始到达第n个楼梯的方式(楼梯号0)。

要获得stair n,首先必须到达开始n-1n-2
类似于到达楼梯n-1,您需要到达n-2n-3楼梯,并且递归就像这样.......

但它必须在某个地方停止,否则你继续评估f(-1)f(-2),... f(- infinity) ...所以有stopping condition:到达{ {1}},您只能在stair 1步骤中执行此操作,即直接从1stair 0

stair 1stair 22 ways + stair 0步,2 + stair 1步。

因此

1

答案 5 :(得分:0)

关于这种递归特别令人困惑的一件事是,它是根据常量SMALL_STEPLARGE_STEP进行参数化的,但终止条件(if (numsteps < 4))只是正确的对于SMALL_STEP = 1LARGE_STEP = 2的具体值 - 如果更改其中任何一个,则代码不正确。可以说代码应该

int CountWays(int numStairs) {
    if (numStairs < 0) {
        return 0;
    } else if (numStairs == 0) {
        return 1;
    } else {
        return CountWays(numStairs - SMALL_STEP) + CountWays(numStairs - LARGE_STEP);
    }
}

效率稍差(需要几次额外的迭代才能得到答案)但仍具有相同的渐近复杂度 - O(2 n