【Leetcode】1096. Brace Expansion II

题目地址:

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;
  }
};

时空复杂度取决于具体输入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值