【2】展开字符串(栈、递归)

#include <iostream>
#include <string>
#include<ctype.h>
using namespace std;
/*
思路:
此题可以将原字符串看成:数字和括号内的字符串,数字和单个字母 的这两个组合,就是重复输出括号内的字符串和单个字母的任务。
所以我们应该先将前面的数字字符串处理成数字,对于没有数字的情况,我们默认为1。
不难想到括号内的字符串我们可以用递归来实现,递归外应该用循环来遍历整个字符串,遇到单个字母我们直接输出;
其中因为只重复输出括号内的内容,我们应添加一个循环条件:非右括号才可以;
所以当我们遍历完整个括号内的字符串后,应该把右括号后一个位置的索引值赋给循环迭代的索引值,
说明我们括号内的字符串已经输出完毕,应当处理后面的字符串了。
*/
string str;
int dfs(int idx){ //循环内套递归,实质上仅遍历一次
    char ch;
    int cnt;
    for (ch = str[idx++]; ch != ')' && idx < str.size(); ch = str[idx++]){
        //因只单次处理括号的内容,所以设置右括号为跳出条件
        for (cnt = 0; isdigit(ch); ch = str[idx++]) cnt = cnt * 10 + ch - '0'; // 是数字的情况
        if (!cnt) cnt = 1; //
        //数字后不是左括号就是字母
        if (ch == '('){  // 是左括号的情况,就递归输出cnt次的括号里的内容(哪怕前面无数字,cnt也为1)
            int tmp;
            while (cnt--)
                tmp = dfs(idx);
            idx = tmp;   //匹配的右括号后面一个位置
        }
        else while (cnt--) cout << ch; //是字母的情况,就输出cnt次的字母(哪怕前面无数字,cnt也为1)
    }
    if (ch == ')') return idx;
}

int main(){
    int t;
    cin >> t;
    while (t--){
        cin >> str;
        dfs(0);
        cout << endl;
    }
    system("pause");
    return 0;
View Code

问题描述:在纺织CAD系统开发过程中,经常会遇到纱线排列的问题。
该问题的描述是这样的:常用纱线的品种一般不会超过25种,所以分别可以用小写字母表示不同的纱线,例如:abc表示三根纱线的排列;重复可以用数字和括号表示,例如:2(abc)表示abcabc;1(a)=1a表示a;2ab表示aab;如果括号前面没有表示重复的数字出现,则就可认为是1被省略了,如:cd(abc)=cd1(abc)=cdabc;这种表示方法非常简单紧凑,也易于理解;但是计算机却不能理解。为了使计算机接受,就必须将简单紧凑的表达方式展开。某ACM队接受了此项任务。现在你就是该ACM队的一员,请你把这个程序编写完成。
已知条件:输入的简单紧凑表达方式的长度不超过250个字符;括号前表示重复的数不超过1000;不会出现除了数字、括号、小写字母以外的任何其他字符;不会出现括号不配对等错误的情况(错误处理已由ACM其他队员完成了)。

思路:利用栈对括号进行存取

用递归的思想展开字符串:

1.for (ch = str[idx++]; ch != ')' && idx < str.size(); ch = str[idx++])

  学习了一种新的使用for循环的形式,idx++先赋值再加1,括号里第1项和第3项使得字符一直向后遍历到结束。

2.if (!cnt) cnt = 1;

  这种用法的意思是:如果cnt为0,则让cnt=1。

3.while (cnt--) cout << ch;

  这种用法表示cnt自减到0(注意:是自减到0!),跳出循环。for(int n=3;n>0;n--)等价于 int n=3;while(n--){n>0}。

原文地址:https://www.cnblogs.com/hl220284/p/10507784.html