【问题来源】网传的2017网易秋招笔试题
【问题描述】
【算法思路】
下面的解题思路摘自 http://www.cnblogs.com/Atanisi/p/7500186.html
刚看到题我就想到暴力解,深搜出所有合法的括号序列,再依次比较公共子序列的长度,返回最长的。但是深搜一般和路径有关,这道题仅仅需要最大公共子序列的长度。而我们发现最大公共子序列的长度就是 s.size() - 1(当且仅当修改距离为 1 时 LCS 最大), 那么我们就想到,可以变换 s 中一个括号的位置,枚举所有的最大公共子序列长度的序列,只是需要判断是否合法。注意到,深搜是枚举所有合法的相同长度的序列,然后我们再在这个集合中去最长的。而后一种思路是我们枚举所有最长公共子序列的序列,然后再在这个集合中去掉非法的和重复的。
因为是 s, t 长度相同,并且 t 也是合法的括号序列,所以正反括号数跟原来一样。考虑在原序列上枚举一个字符,把这个插入依次到序列的某个位置去,其他序列相对顺序不变,,这样就可以让LCS最大,然后我们判断一下是否合法(这里有个小技巧),去重就用 set。
【代码】
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() { 6 string s; 7 cin >> s; 8 set<string> m; 9 int n = s.size(); 10 for (int i = 0; i < n; ++i) { 11 string w = s.substr(0, i) + s.substr(i + 1); 12 for (int j = 0; j < n - 1; ++j) { 13 string tmp = w.substr(0, j) + s[i] + w.substr(j); 14 int num = 0; 15 for (int k = 0; k < n; ++k) { 16 num += (tmp[k] == '(' ? 1 : -1); 17 if (num < 0) 18 break; 19 } 20 if (num >= 0) 21 m.insert(tmp); 22 } 23 } 24 cout << (int)m.size() - 1 << endl; 25 26 return 0; 27 }