面试碰到的题,大意如下:
机器人上楼梯,每步可以走1阶,2阶或者3阶,求n阶楼梯有多少种走法,列出全部走法.
思路:
当时想通了怎么计算多少种走法,但对于把全部走法列出来却没有什么头绪,脑子中就是觉得这题要用到递归或则是动态规划.
f(1) 1; f(2) 1,1; 2; f(3) 1,2; 1,1,1; 2,1; 3; f(4) 1 f(3) 2 f(2) 3 f(1) f(5) 1 f(4) 2 f(3) 3 f(2)
仔细分析,发现题目和阶乘很相似.分别列举1,2,3阶楼题的走法,作为基础..
n阶(n>3),只需要考虑第一步怎么走,第一步无非就三种选择,
1阶,2阶,3阶
程序设计思路:
为了避免重复计算,采用自底向上解决方案
先求解子问题再根据子问题的解来求解父问题,参考
/** * * parameter:n,具体的台阶数 * 字符串数组a[] 存放所有可能的走法 */ void step(string a[], int n){ string temp1, temp2, temp3; a[1] = "1;"; a[2] = "1,1;2;"; a[3] = "1,2;1,1,1;2,1;3;"; for (int i = 4; i <= n; i++){ temp1 = splitAndAdd("1,", a[i-1], ";"); temp2 = splitAndAdd("2,", a[i-2], ";"); temp3 = splitAndAdd("3,", a[i-3], ";"); a[i] = temp1 + temp2 + temp3; } print_result(a[n]); }
为避免重复求解,使用字符串数组存放每阶的走法,为便于后续处理,不同走法之间以";"分割,字符串中;有多少个就代表有多少种走法
显然a[4] = 1,a[3] + 2,a[2]+ 3,a[1]
a[4]的所有解法如下,关键在于怎么把1,2,3加到每种解法的前面
1, 1,2 1, 1,1,1 1, 2,1 1, 3 2, 1,1 2, 2 3, 1
设计函数splitAndAdd,该函数主要思路将原来的解法字符串根据";"进行切片,得到个每种解法并保存,然后遍历每种解法,加上新的步法,并补充分隔符";"
注:c++ 没有像java现成的切片函数,借用c中的strtok实现,可参考
1 /** 2 * 3 * parameter:pre,要加入的字符 4 * str,已有解法字符串 5 * pattern,各种解法的分隔符 6 */ 7 8 string splitAndAdd(string pre, string &str, string pattern){ 9 string res; 10 std::vector<std::string> resultVec; 11 char * strc = new char[strlen(str.c_str()) + 1]; 12 strcpy_s(strc, strlen(str.c_str()) + 1, str.c_str()); 13 14 char* tmpStr = strtok(strc, pattern.c_str()); 15 while (tmpStr != NULL) 16 { 17 resultVec.push_back(pre + std::string(tmpStr)); 18 tmpStr = strtok(NULL, pattern.c_str()); 19 } 20 for (string s : resultVec){ 21 res += s + ";"; 22 } 23 return res; 24 }
程序运行结果:5阶梯为例
1,1,1,2 1,1,1,1,1 1,1,2,1 1,1,3 1,2,1,1 1,2,2 1,3,1 2,1,2 2,1,1,1 2,2,1 2,3 3,1,1 3,2 total path num:13
完整程序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<string> #include<vector> using std::cin; using std::cout; using std::endl; using std::string; using std::vector; /** * * parameter:pre,要加入的字符 * str,已有解法字符串 * pattern,各种解法的分隔符 */ string splitAndAdd(string pre, string &str, string pattern){ string res; std::vector<std::string> resultVec; char * strc = new char[strlen(str.c_str()) + 1]; strcpy_s(strc, strlen(str.c_str()) + 1, str.c_str()); char* tmpStr = strtok(strc, pattern.c_str()); while (tmpStr != NULL) { resultVec.push_back(pre + std::string(tmpStr)); tmpStr = strtok(NULL, pattern.c_str()); } for (string s : resultVec){ res += s + ";"; } return res; } void print_result(string &res){ string strs = res; size_t pos = res.find(";"); size_t size = res.size(); int count = 0; while (pos != std::string::npos){ count++; cout << strs.substr(0, pos) << endl; strs = strs.substr(pos + 1, size); pos = strs.find(";"); } cout << endl << "total path num:" << count << endl; } /** * * parameter:n,具体的台阶数 * 字符串数组a[] 存放所有可能的走法 */ void step(string a[], int n){ string temp1, temp2, temp3; a[1] = "1;"; a[2] = "1,1;2;"; a[3] = "1,2;1,1,1;2,1;3;"; for (int i = 4; i <= n; i++){ temp1 = splitAndAdd("1,", a[i-1], ";"); temp2 = splitAndAdd("2,", a[i-2], ";"); temp3 = splitAndAdd("3,", a[i-3], ";"); a[i] = temp1 + temp2 + temp3; } print_result(a[n]); } #define N 1000 int main() { string steps[N]; step(steps, 5); return 0; }