楼梯问题:如何打印组合?

Posted

技术标签:

【中文标题】楼梯问题:如何打印组合?【英文标题】:Staircase problem: How to print the combinations? 【发布时间】:2019-02-09 17:28:26 【问题描述】:

问题:

在这个问题中,我们正在评估的场景如下:您站在楼梯的底部,并且正在前往顶部。小步走上一级台阶,大步走两级。您想根据大小步幅的不同组合计算爬上整个楼梯的方式的数量。例如,三级楼梯可以通过三种不同的方式爬上:三小步、一小步后一大步或一大步后一小步。

waysToClimb(3) 的调用应该产生以下输出:

1 1 1,
1 2,
2 1

我的代码:

public static void waysToClimb(int n)
    if(n == 0) 
        System.out.print("");
    else if(n == 1)
        System.out.print("1");
    else 
        System.out.print("1 "); 
        waysToClimb(n - 1);
        System.out.print(",");
        System.out.print("2 ");
        waysToClimb(n - 2);
    

我的输出:

1 1 1,
2,
2 1

我的递归似乎不记得它采取的路径知道如何修复它?

编辑:

谢谢大家的回复。抱歉回复晚了

我想通了

public static void waysToClimb(int n)

    String s ="[";
    int p=0;
    com(s,p,n);



public static void com(String s,int p,int n)

    if(n==0 && p==2)

    System.out.print(s.substring(0,s.length()-2)+"]");

    else if(n==0 && p !=0)

    System.out.print(s+"");

    else if(n==0 && p==0)

    System.out.print("");

    else if(n==1)

    System.out.print(s+"1]");

    else 

        com(s+"1, ",1,n-1);
        System.out.println();
        com(s+"2, ",2,n-2);

    


【问题讨论】:

问题指出您应该计算不同方式的数量,而不是打印它们。哪个是预期的输出? 你不计算(总结步数) - 每次调用waysToClimb 都会将可能的步数加 1,除非你还剩 0 步。你把增量放在哪里只是你必须做出的决定(你只需要注意不要计算两次)。 当心下面的答案并没有很好地涵盖问题的核心(循环语义或者如果你知道的话还有一个数学解决方案) 【参考方案1】:

如果您明确想要打印所有路径(不同于计算路径或查找特定路径),则需要将它们一直存储到 0。

public static void waysToClimb(int n, List<Integer> path)

    if (n == 0)
    
        //  print whole path
        for (Integer i: path)
        
            System.out.print(i + " ");
        
        System.out.println();
    
    else if (n == 1)
    
        List<Integer> newPath = new ArrayList<Integer>(path);
        newPath.add(1);
        waysToClimb(n-1, newPath);
    
    else if (n > 1)
    
        List<Integer> newPath1 = new ArrayList<Integer>(path);
        newPath1.add(1);
        waysToClimb(n-1, newPath1);

        List<Integer> newPath2 = new ArrayList<Integer>(path);
        newPath2.add(2);
        waysToClimb(n-2, newPath2);
    

初始调用:waysToClimb(5, new ArrayList&lt;Integer&gt;());

【讨论】:

【参考方案2】:

下面提到的解决方案将类似于深度优先搜索,它将探索一条路径。一旦路径完成,它将回溯并探索其他路径:

public class Demo 
    private static LinkedList<Integer> ll = new LinkedList<Integer>() add(1);add(2);;

    public static void main(String args[]) 
        waysToClimb(4, "");
    

    public static void waysToClimb(int n, String res) 
        if (ll.peek() > n)
            System.out.println(res);
        else 
            for (Integer elem : ll) 
                if(n-elem >= 0)
                    waysToClimb(n - elem, res + String.valueOf(elem) + " ");
            
        
    

【讨论】:

【参考方案3】:
public class Test2 

    public int climbStairs(int n) 
        // List of lists to store all the combinations
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        // initially, sending in an empty list that will store the first combination
        csHelper(n, new ArrayList<Integer>(), ans);
        // a helper method to print list of lists
        print2dList(ans);
        return ans.size();
    

    private void csHelper(int n, List<Integer> l, List<List<Integer>> ans) 
        // if there are no more stairs to climb, add the current combination to ans list
        if(n == 0) 
            ans.add(new ArrayList<Integer>(l));
        

        // a necessary check that prevent user at (n-1)th stair to climb using 2 stairs
        if(n < 0) 
            return;
         

        int currStep = 0;
        // i varies from 1 to 2 as we have 2 choices i.e. to either climb using 1 or 2 steps
        for(int i = 1; i <= 2; i++) 
            // climbing using step 1 when i = 1 and using 2 when i = 2
            currStep += 1;
            // adding current step to the arraylist(check parameter of this method)
            l.add(currStep);
            // make a recursive call with less number of stairs left to climb
            csHelper(n - currStep, l, ans);
            l.remove(l.size() - 1);
        
    

    private void print2dList(List<List<Integer>> ans) 
        for (int i = 0; i < ans.size(); i++)  
            for (int j = 0; j < ans.get(i).size(); j++)  
                System.out.print(ans.get(i).get(j) + " "); 
             
            System.out.println(); 
        
    

    public static void main(String[] args) 
        Test2 t = new Test2();
        t.climbStairs(3);
    

请注意,此解决方案对于较大的输入将超时,因为这不是一个记忆递归解决方案,并且可以抛出 MLE(因为我在找到组合时创建一个新列表)。

希望这会有所帮助。

【讨论】:

【参考方案4】:

如果有人正在寻找 python 解决方案,对于这个问题。

def way_to_climb(n, path=None, val=None):
    path = [] if path is None else path
    
    val = [] if val is None else val
    if n==0:
       val.append(path)
    elif n==1:
        new_path = path.copy()
        new_path.append(1)
        way_to_climb(n-1, new_path, val)
        
    elif n>1:
        new_path1 = path.copy()
        new_path1.append(1)
        
        way_to_climb(n-1, new_path1, val)
        
        new_path2 = path.copy()
        new_path2.append(2)
        
        way_to_climb(n-2, new_path2, val)
    return val

注意:它基于@unlut 解决方案,这里 OP 使用了自上而下的递归方法。这个解决方案适用于所有在 python 中寻找所有楼梯问题组合的人,没有 python 问题,所以我在这里添加了一个 python 解决方案

如果我们使用自下而上的方法并使用记忆,那么我们可以更快地解决问题。

【讨论】:

【参考方案5】:

即使您确实找到了代码问题的正确答案,您仍然可以通过仅使用一个 if 来检查剩余步数是否为 0 来改进它。我使用了一个开关来检查所采取的步数,因为只有 3 个选项,0、1 或 2。我还重命名了用于使第一次看到代码的人更容易理解代码的变量,因为如果您只使用一个字母变量名,这会很混乱.即使所有这些更改代码运行相同,我只是认为为将来可能会查看此问题的其他人添加其中一些内容可能会更好。

public static void climbStairsHelper(String pathStr, int stepsTaken, int stepsLeft)

    if(stepsLeft == 0)
    
        switch(stepsTaken)
        
            case 2:
                System.out.print(pathStr.substring(0, pathStr.length() - 2) + "]");
                break;
            case 1:
                System.out.print(pathStr + "");
                break;
            case 0:
                System.out.print("");
                break;
        
    
    else if(stepsLeft == 1)
    
        System.out.print(pathStr + "1]");
    
    else 
    
        climbStairsHelper(pathStr + "1, ", 1, stepsLeft - 1);
        System.out.println();
        climbStairsHelper(pathStr + "2, ", 2, stepsLeft - 2);
    

`

`

【讨论】:

以上是关于楼梯问题:如何打印组合?的主要内容,如果未能解决你的问题,请参考以下文章

练习四十三:打印楼梯

爬楼梯问题【多解法】

【算法题】12.爬楼梯问题

2041-超级楼梯(斐波那契)/(排列组合)

回溯解决爬楼梯问题

动态规划-爬楼梯问题