机器人上楼梯

面试碰到的题,大意如下:

机器人上楼梯,每步可以走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

完整程序

#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;
}
View Code

 

posted @ 2017-09-20 20:58  疾风剑  阅读(422)  评论(0编辑  收藏  举报