Finding all paths down stairs?

后端 未结 13 1383
天命终不由人
天命终不由人 2020-12-13 07:21

I was given the following problem in an interview:

Given a staircase with N steps, you can go up with 1 or 2 steps each time. Output all possible way

相关标签:
13条回答
  • 2020-12-13 07:55

    It's a weighted graph problem.

    • From 0 you can get to 1 only 1 way (0-1).
    • You can get to 2 two ways, from 0 and from 1 (0-2, 1-1).
    • You can get to 3 three ways, from 1 and from 2 (2 has two ways).
    • You can get to 4 five ways, from 2 and from 3 (2 has two ways and 3 has three ways).
    • You can get to 5 eight ways, ...

    A recursive function should be able to handle this, working backwards from N.

    0 讨论(0)
  • 2020-12-13 07:56

    Here is a simple solution to this question in very simple CSharp (I believe you can port this with almost no change to Java/C++). I have added a little bit more of complexity to it (adding the possibility that you can also walk 3 steps). You can even generalize this code to "from 1 to k-steps" if desired with a while loop in the addition of steps (last if statement).

    I have used a combination of both dynamic programming and recursion. The use of dynamic programming avoid the recalculation of each previous step; reducing the space and time complexity related to the call stack. It however adds some space complexity (O(maxSteps)) which I think is negligible compare to the gain.

    /// <summary>
    /// Given a staircase with N steps, you can go up with 1 or 2 or 3 steps each time.
    /// Output all possible way you go from bottom to top
    /// </summary>
    public class NStepsHop
    {
        const int maxSteps = 500;  // this is arbitrary
        static long[] HistorySumSteps = new long[maxSteps];
    
        public static long CountWays(int n)
        {
            if (n >= 0 && HistorySumSteps[n] != 0)
            {
                return HistorySumSteps[n];
            }
    
            long currentSteps = 0;
            if (n < 0)
            {
                return 0;
            }
            else if (n == 0)
            {
                currentSteps = 1;
            }
            else
            {
                currentSteps = CountWays(n - 1) + 
                               CountWays(n - 2) + 
                               CountWays(n - 3);
            }
    
            HistorySumSteps[n] = currentSteps;
            return currentSteps;
        }
    }
    

    You can call it in the following manner

    long result;
    result = NStepsHop.CountWays(0);    // result = 1
    result = NStepsHop.CountWays(1);    // result = 1
    result = NStepsHop.CountWays(5);    // result = 13
    result = NStepsHop.CountWays(10);   // result = 274
    result = NStepsHop.CountWays(25);   // result = 2555757
    

    You can argue that the initial case when n = 0, it could 0, instead of 1. I decided to go for 1, however modifying this assumption is trivial.

    0 讨论(0)
  • 2020-12-13 07:58

    the problem can be solved quite nicely using recursion:

    void printSteps(int n)
    {
       char* output = new char[n+1];
       generatePath(n, output, 0);
       printf("\n");
    }
    
    void generatePath(int n, char* out, int recLvl)
    {
       if (n==0)
       {
          out[recLvl] = '\0';
          printf("%s\n",out);
       }
    
       if(n>=1)
       {
          out[recLvl] = '1';
          generatePath(n-1,out,recLvl+1);
       }
    
       if(n>=2)
       {
          out[recLvl] = '2';
          generatePath(n-2,out,recLvl+1);
       }
    }
    

    and in main:

    void main()
    {
        printSteps(0);
        printSteps(3);
        printSteps(4);
        return 0;       
    }
    
    0 讨论(0)
  • 2020-12-13 08:08

    Complete C-Sharp code for this

     void PrintAllWays(int n, string str) 
        {
            string str1 = str;
            StringBuilder sb = new StringBuilder(str1);
            if (n == 0) 
            {
                Console.WriteLine(str1);
                return;
            }
            if (n >= 1) 
            {
                sb = new StringBuilder(str1);
                PrintAllWays(n - 1, sb.Append("1").ToString());
            }
            if (n >= 2) 
            {
                sb = new StringBuilder(str1);
                PrintAllWays(n - 2, sb.Append("2").ToString());
            }
        }
    
    0 讨论(0)
  • 2020-12-13 08:08

    Late C-based answer

    #include <stdio.h>
    #include <stdlib.h>
    #define steps 60
    static long long unsigned int MAP[steps + 1] = {1 , 1 , 2 , 0,};
    
    static long long unsigned int countPossibilities(unsigned int n) {
        if (!MAP[n]) {
           MAP[n] = countPossibilities(n-1) + countPossibilities(n-2);
        }
        return MAP[n];
    }
    
    int main() {
       printf("%llu",countPossibilities(steps));
    }
    
    0 讨论(0)
  • 2020-12-13 08:13

    Great answer by @templatetypedef - I did this problem as an exercise and arrived at the Fibonacci numbers on a different route:

    The problem can basically be reduced to an application of Binomial coefficients which are handy for Combination problems: The number of combinations of n things taken k at a time (called n choose k) can be found by the equation

    enter image description here

    Given that and the problem at hand you can calculate a solution brute force (just doing the combination count). The number of "take 2 steps" must be zero at least and may be 50 at most, so the number of combinations is the sum of C(n,k) for 0 <= k <= 50 ( n= number of decisions to be made, k = number of 2's taken out of those n)

    BigInteger combinationCount = 0;
    for (int k = 0; k <= 50; k++)
    {
        int n = 100 - k;
        BigInteger result = Fact(n) / (Fact(k) * Fact(n - k));
        combinationCount += result;
    }
    

    The sum of these binomial coefficients just happens to also have a different formula:

    enter image description here

    0 讨论(0)
提交回复
热议问题