JAVA_上楼梯_爬楼梯 1 2 3

题目: 楼梯总共N阶,小明可以一次可以跨1步,2步,3步,请用递归求出小明总共有多少种跨法走完这个楼梯。

实例:   输入:4   输出4或者7

总梯数为4: 可能的走法.

1 1 1 1

1 1 2

1 2 1

1 3

2 2

2 1 1

3 1

上面为7中走法,  如果将 1 1 2 和1 2 1及 2 1 1看成相同的,则只有四种走法.

方式1: 回溯法

先按照1走完,当走完4步后,将结果存放list中. 回退一步, 查询有没有可能两步的走法. 依次会退. 

方式2:斐波那契数列

思路: 第n-2步到n有几种方法

方式3:非递归操作

上代码:    去重的在方式1中

package com.java.springbootdemo.huawei.louti;

import java.util.ArrayList;
import java.util.Collections;
import java.util.TreeSet;

/**
 * 笔试题:楼梯总共N阶,小明可以一次可以跨1步,2步,3步,请用递归求出小明总共有多少种跨法走完这个楼梯。
 *  
 */
public class StairsTest {

    //楼梯总数为N阶
    int starisNum = 5;

    //总共有1步,2步,3步这几种跨法
    int[] ways = {1, 2, 3};


    //统计总共有多少种跨法
    int count = 0;

    //记录每次的具体步数
    ArrayList<Integer> list = new ArrayList<Integer>();
    ArrayList<Integer> list1 = new ArrayList<Integer>();
    TreeSet<String> strs = new TreeSet<>();

    public StairsTest() {
    }

    public StairsTest(int starisNum) {
        this.starisNum = starisNum;
    }

    /**
     * * @param tempSteps: 暂时走到第几个台阶了
     *      
     */

    void getSum(int tempSteps) {

        if (tempSteps > starisNum)return;

        //达到要求了,计数加一,并输出具体的步数
        if (tempSteps == starisNum) {
            count++;
            System.out.println(count + " 具体步法为:" + list);
            list1.addAll(list);
            Collections.sort(list1);
            String str = list1.toString();
            strs.add(str);
            list1.clear();
            return;
        }

        //到达一个状态时,都先尝试走下所有的分支可能,然后再依次回退,这样就可以回溯遍历所有的可能了
        for (int i = 0; i < ways.length; i++) {
            list.add(ways[i]);
            tempSteps += ways[i];
            getSum(tempSteps);
            tempSteps -= ways[i];
            list.remove(list.size() - 1);
        }

    }


    /**
     *      * 2. 参考网上的方法:类似斐波那契数列的递归方法,应用的是动态规划的思想,一个状态可由前面的状态求出
     *      * 不过这种方式没法打印出具体的步法,只能是一个总的步数
     *      *
     *      * 估计面试官可能想要的是这个答案
     *      *
     *      * 走到第k阶, 往前只回退一步,只有三种走法:
     *      * a) 从k-1阶梯,步子大小为1
     *      * b) 从k-2阶梯,步子大小为2
     *      * c) 从k-3阶梯,步子大小为3
     *      * 所以自然第k阶的玩法就是:getSum2(n - 1) + getSum2(n - 2) + getSum2(n - 3)
     *      *
     *      * @param args: n 走到第n阶时可以有多少种走法
     *      
     */

    int getSum2(int n) {
        switch (n) {
            case 1:
                return 1;
            case 2:
                return 2;
            case 3:
                return 4;
            default:
                return getSum2(n - 1) + getSum2(n - 2) + getSum2(n - 3);
        }
    }


     /***
         * 3. 思想类似方法二
         * 既然这个可以看作经典的那个斐波那契数列的变形,那么自然也就有非递归的玩法了
         *
         * @param n
         * @return
         */
    int getSum3(int n) {
        switch (n) {
            case 1:
                return 1;
            case 2:
                return 2;
            case 3:
                return 4;
            default:
                int result = 0;
                //当然也可以kind数组也可以申请为n位,kind[n-1]就表示为n阶楼梯的走法,只是这么浪费空间而已
                int[] kind = {1, 2, 4};
                for (int i = 4; i <= n; i++) {
                    result = kind[0] + kind[1] + kind[2];
                    kind[0] = kind[1];
                    kind[1] = kind[2];
                    kind[2] = result;
                }
                return result;
        }
    }


    public static void main(String[] args) {

        StairsTest st = new StairsTest(10);

        //方法一:回溯法,递归
        st.getSum(0);
        System.out.println("a) 总共的步数:" + st.count);
        System.out.println("----------------------------------");
        // System.out.println(st.strs);
        for (String str : st.strs) {
            System.out.println(str);
        }
        System.out.println(st.strs.size());
        System.out.println("----------------------------------");

        //方法二:动态规划,类似斐波那契数列,递归
        System.out.println("\nb) 总共的步数:" + st.getSum2(st.starisNum));

        //方法三:动态规划,类似斐波那契数列,非递归
        System.out.println("\nc) 总共的步数:" + st.getSum3(st.starisNum));

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值