题目: 楼梯总共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));
}
}