题目描述
如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。
花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串,定义下面几条语法规则:
- 如果只给出单一的元素 x,那么表达式表示的字符串就只有 “x”。R(x) = {x}
- 例如,表达式 “a” 表示字符串 “a”。
- 而表达式 “w” 就表示字符串 “w”。
- 当两个或多个表达式并列,以逗号分隔,我们取这些表达式中元素的并集。R({e_1,e_2,…}) = R(e_1) ∪ R(e_2) ∪ …
- 例如,表达式 “{a,b,c}” 表示字符串 “a”,“b”,“c”。
- 而表达式 “{{a,b},{b,c}}” 也可以表示字符串 “a”,“b”,“c”。
- 要是两个或多个表达式相接,中间没有隔开时,我们从这些表达式中各取一个元素依次连接形成字符串。R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}
- 例如,表达式 “{a,b}{c,d}” 表示字符串 “ac”,“ad”,“bc”,“bd”。
- 表达式之间允许嵌套,单一元素与表达式的连接也是允许的。
- 例如,表达式 “a{b,c,d}” 表示字符串 “ab”,“ac”,"ad"。
- 例如,表达式 “a{b,c}{d,e}f{g,h}” 可以表示字符串 “abdfg”, “abdfh”, “abefg”, “abefh”, “acdfg”, “acdfh”, “acefg”, “acefh”。
给出表示基于给定语法规则的表达式 expression,返回它所表示的所有字符串组成的有序列表。
假如你希望以「集合」的概念了解此题,也可以通过点击 “显示英文描述” 获取详情。
示例 1:
输入:expression = "{a,b}{c,{d,e}}"
输出:["ac","ad","ae","bc","bd","be"]
示例 2:
输入:expression = "{{a,z},a{b,c},{ab,z}}"
输出:["a","ab","ac","z"]
解释:输出中 不应 出现重复的组合结果。
提示:
- 1 <= expression.length <= 60
- expression[i] 由 ‘{’,‘}’,‘,’ 或小写英文字母组成
- 给出的表达式 expression 用以表示一组基于题目描述中语法构造的字符串
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/brace-expansion-ii
题目分析
个人瞎想
糟了,完全不了解shell编程
大概的思路是从头开始按顺序处理每个大括号内的内容,然后根据后大括号后面连接的第一个字符的类型确定接下来做什么操作。
所以首先实现大括号的匹配。考虑到表达式之间允许嵌套,引入递归。从未处理过的第一个前大括号向后遍历,若读到小写字母或者逗号则执行相关操作,若读到另一个前大括号则调用递归。读到后括号时返回上一级,继续向后遍历。保存每个大括号内的阶段性结果,直到返回到最高级的大括号,再把阶段性结果写到ret中
共有连接和取并集两种操作,可以使用一个标志位记录当前操作,每次读完一组大括号后更新标志位,初始操作为连接。
- 在上一个后大括号后面直接连接字符或者另一个前大括号时,执行连接操作。从已有字符串集合和新读入的大括号表示的集合中各取一个元素进行连接
- 执行取并集操作时,将读入和字符和当前大括号中的已处理的字符对比,若没出现过则保存到阶段性结果中
但是没想好怎么记录层数,以及感觉每次递归都要申请新的空间有点浪费。先去学习一下别的题解,有空再试试
题解
还是学习ylb的题解,关注TA了。
思路是每次查找子串中的第一个后括号,再从后括号出发反向查找第一个正括号。感觉很聪明,因为找到的第一个后括号肯定是嵌套最深的一组括号。如果找不到后花括号,说明当前子串为小写字母字符元素,直接加到结果字符串里。
查找当前花括号中的逗号,划分为不同子串,将各个子串与花括号外的前缀和后缀连接得到新的表达式,对其进行递归
class Solution {
public:
vector<string> braceExpansionII(string expression) {
dfs(expression);
return vector<string>(s.begin(), s.end());
}
private:
set<string> s;
void dfs(string exp) {
int j = exp.find_first_of('}');
if (j == string::npos) { //npos表示字符串的结束
s.insert(exp);
return;
}
int i = exp.rfind('{', j);
string a = exp.substr(0, i); //前缀
string c = exp.substr(j + 1); //后缀
stringstream ss(exp.substr(i + 1, j - i - 1));
string b;
while (getline(ss, b, ',')) { //ss为输入流,b保存输入流中的信息,','为截断符
dfs(a + b + c);
}
}
};
作者:lcbin
链接:https://leetcode.cn/problems/brace-expansion-ii/solution/python3javacgotypescript-yi-ti-yi-jie-di-gs64/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结
难度为困难的题还是做不动。
之前做过一个生成小括号的题,好像与本题有一点点像,但是像的不多。题解中寻找后括号而不是找前括号,真的很提高效率啊,感觉我还是太线性思维了,很难换种方向思考。