题目地址:
https://leetcode.com/problems/brace-expansion-ii/description/
给定一个表达式,其只含下面的字符{},
和英文小写字母。小写字母可以视为单元集合,,
可以视为集合加法,{}
包围的一段是一个集合,集合之间如果是直接连接而不是隔着一个,
,则视为是集合乘法,即笛卡儿乘积。两个字符串乘积即为拼接。问该表达式最后展开的集合是什么。集合需要去重。题目保证表达式合法。
其实就是表达式求值。该表达式只含加法、乘法和括号,和普通数字的含加法乘法括号的求值是一样的。例如,对于 a + b × c + d a+b\times c+d a+b×c+d这个表达式,维护两个数 ( x , y ) (x,y) (x,y),这个数对表示当前表达式的值是 x + y x+y x+y,但是 y y y还没有加进 x x x中去,原因是后面可能跟乘号 × \times ×。一开始数对是 ( 0 , 1 ) (0,1) (0,1)(即加法单位元和乘法单位元),并且规定最左边有个乘号(即表达式视为 1 × a + b × c + d 1\times a+b\times c+d 1×a+b×c+d)。接着遍历表达式,遍历到 a a a的时候,由于第一个数默认前面跟乘号,状态变为 ( 0 , a ) (0,a) (0,a),再后面是 + b +b +b,我们已经确定了 a a a后面是加法了,从而可以安全的把 a a a加上去,从而状态变为 ( a , b ) (a,b) (a,b);再后面是 × c \times c ×c, c c c要乘在 b b b后面,状态变为 ( a , b c ) (a,bc) (a,bc);再后面是 + d +d +d,于是我们知道了 b c bc bc可以加到前面了,从而状态变为 ( a + b c , d ) (a+bc,d) (a+bc,d)。遍历完毕,最后结果就是 a + b c + d a+bc+d a+bc+d。
同理,本题也是一样的步骤。字符串集合的加法和乘法已经定义了,加法为集合取并,乘法是取笛卡儿积形成新的字符串集合。这个代数结构形成一个环。初始状态为
(
{
}
,
{
"
"
}
)
(\{\},\{""\})
({},{""})(空集为加法单位元,只含空串的集合为乘法单位元),并且一开始的运算符规定为乘法。在遍历到{
的时候,递归求解与这个左括号配对的右括号包围起来的部分的值,求好了之后,看一下这一段的前面的符号,如果前面无符号,或者不是,
,则为乘法,否则是加法;如果遍历到了逗号,则直接略过;如果遍历到了字符,则将字符串截取出来。代码如下:
class Solution {
public:
using SS = unordered_set<string>;
SS add(SS& a, SS& b) {
SS c = a;
for (auto& x : b)
if (x.size()) c.insert(x);
return c;
}
SS mul(SS& a, SS& b) {
SS c;
for (auto& x : a)
for (auto& y : b)
if (x.size() || y.size()) c.insert(x + y);
return c;
}
SS dfs(int& k, string& e) {
SS a, b;
b.insert("");
while (k < e.size() && e[k] != '}') {
bool is_add = true;
// c存下一个要处理的集合
SS c;
if (e[k] == ',') {
k++;
continue;
}
// 如果是开头,或者不是',',则说明是乘法
if (!k || e[k - 1] != ',') is_add = false;
if (e[k] == '{') {
// 如果遇到了'{',就是要递归求解新的一段了,先看一下符号。
// 略过'{',接着递归求解
c = dfs(++k, e);
// 求解完略过'}'
k++;
} else {
// 如果遇到了字符,截取出字符串
string s;
while (k < e.size() && 'a' <= e[k] && e[k] <= 'z') s += e[k++];
c.insert(s);
}
// c这个集合已经求出了,根据其前面是加法还是乘法,更新状态
is_add ? a = add(a, b), b = c : b = mul(b, c);
}
// 求完一个整个的表达式之后,把状态更新为集合
return add(a, b);
}
vector<string> braceExpansionII(string e) {
int k = 0;
auto v = dfs(k, e);
vector<string> res(v.begin(), v.end());
sort(res.begin(), res.end());
return res;
}
};
时空复杂度取决于具体输入。