problem1 link
首先去掉原串中已经配对的括号,那么剩下的括号序列是以下情况:(1)空串;(2)))));(3)((((;(4)))))((。第一种情况不需要处理。对于第三种情况和第四种情况,都可以将其变成第二种情况。第二种情况只需要对前一半做操作即可。另外,每次操作的时候不会影响已经删掉的匹配的串。
problem2 link
(1)首先,如果$[x,y_{1}],[x,y_{2}],y_{1}< y_{2}$都要是匹配的,那么有$[x,y_{1}],[y_{1}+1,y_{2}]$之间要分别匹配。
(2)其次,如果$[x_{1},y_{1}],[x_{2},y_{2}]$都要匹配,$x_{1}<x_{2}<y_{1}<y_{2}$,那么$[x_{1},x_{2}-1],[x_{2},y_{1}],[y_{1}+1,y_{2}]都要匹配$
经过这样的处理,最后所有匹配的区间可能会有包含的关系,然后没有其他相交关系。所以可以按照区间长度排序,一个区间一个区间进行处理。每个区间都相等于一个小的串(对于包含小区间的大区间不需要考虑已经处理的小区间,只需要考虑除了小区间外其他的部分匹配)。对于一个串$T$,定义$f(T)$表示将$T$变成匹配最少的修改数,这个修改指的是单独把左括号改成右括号或右括号改成左括号的次数,而不是交换。最后的答案其实是重复了一半,除以2即可。还有一个问题是有可能所有考虑的范围内的左括号数过于多,以至于在未考虑区间根本没有足够的右括号可以交换,这种情况是无解的。
problem3 link
这里有一个贪心的思路。
code for problem1
#include <algorithm> #include <queue> #include <string> #include <vector> class ParenthesesDiv1Easy { public: std::vector<int> correct(std::string s) { int n = static_cast<int>(s.size()); if (n % 2 == 1) { return {-1}; } return Dfs(s); } std::vector<int> Dfs(std::string &s) { int n = static_cast<int>(s.size()); std::deque<int> st; for (int i = 0; i < n; ++i) { if (s[i] == '(') { st.push_back(i); } else if (!st.empty() && s[st.back()] == '(') { st.pop_back(); } else { st.push_back(i); } } if (st.empty()) { return {}; } std::vector<int> ans; for (size_t i = 0; i < st.size(); ++i) { if (s[st[i]] == '(') { int L = st[i]; int R = st.back(); ans.push_back(L); ans.push_back(R); Flip(s, L, R); auto r = Dfs(s); for (int x : r) { ans.emplace_back(x); } return ans; } } ans.push_back(st.front()); ans.push_back(*(st.begin() + st.size() / 2 - 1)); return ans; } void Flip(std::string &s, int L, int R) { std::reverse(s.begin() + L, s.begin() + R + 1); for (int i = L; i <= R; ++i) { if (s[i] == '(') s[i] = ')'; else s[i] = '('; } } };
code for problem2
#include <algorithm> #include <string> #include <vector> class ParenthesesDiv1Medium { public: int minSwaps(const std::string &s, const std::vector<int> &L, const std::vector<int> &R) { int n = static_cast<int>(s.size()); int m = static_cast<int>(L.size()); std::vector<int> inside(n); for (int i = 0; i < m; ++i) { ++inside[L[i]]; if (R[i] + 1 < n) { --inside[R[i] + 1]; } } for (int i = 1; i < n; ++i) { inside[i] += inside[i - 1]; } std::vector<std::vector<int>> ends(n); for (int i = 0; i < m; ++i) { ends[L[i]].emplace_back(R[i]); } std::vector<std::pair<int, int>> requests; for (int i = 0; i < n; ++i) { if (ends[i].empty()) { continue; } std::sort(ends[i].begin(), ends[i].end()); ends[i].erase(std::unique(ends[i].begin(), ends[i].end()), ends[i].end()); for (size_t j = 1; j < ends[i].size(); ++j) { ends[ends[i][j - 1] + 1].emplace_back(ends[i][j]); } ends[i].resize(1); int x = ends[i][0]; for (int j = n - 1; j > i; --j) { if (!ends[j].empty() && ends[j].back() >= ends[i][0]) { x = min(x, j - 1); } } if (x < ends[i][0]) { ends[x + 1].emplace_back(ends[i][0]); ends[i][0] = x; } requests.emplace_back(i, ends[i][0]); } int ans = 0; std::sort(requests.begin(), requests.end(), [&](const std::pair<int, int> &a, const std::pair<int, int> &b) { int ll = a.second - a.first; int rr = b.second - b.first; return ll != rr ? ll < rr : a.first < b.first; }); std::string cs = s; for (const auto &e : requests) { int ll = e.first; int rr = e.second; std::string cur_s; for (int j = ll; j <= rr; ++j) { if (cs[j] != '*') { cur_s += cs[j]; cs[j] = '*'; } } int c = Compute(cur_s); if (c == -1) { return -1; } ans += c; } if (total_left > total_len) { ans += total_left - total_len; } else { ans += abs(total_right - total_len); } for (int i = 0; i < n; ++i) { if (inside[i] == 0) { if (s[i] == ')') { --total_left; } else { --total_right; } } } if (total_left > total_len || total_right > total_len) { return -1; } return ans / 2; } int Compute(const std::string &s) { int n = static_cast<int>(s.size()); if (n % 2 == 1) { return -1; } if (n == 0) { return 0; } auto Update = [&](int &x, int y) { if (x == -1 || x > y) { x = y; } }; std::vector<std::vector<int>> dp(n, std::vector<int>(n + 1, -1)); dp[0][1] = s[0] == ')'; for (int i = 1; i < n; ++i) { for (int j = 0; j <= i; ++j) { if (dp[i - 1][j] == -1) { continue; } if (s[i] == '(') { Update(dp[i][j + 1], dp[i - 1][j]); if (j > 0) { Update(dp[i][j - 1], dp[i - 1][j] + 1); } } else { if (j > 0) { Update(dp[i][j - 1], dp[i - 1][j]); } Update(dp[i][j + 1], dp[i - 1][j] + 1); } } } for (char x : s) { if (x == '(') { ++total_left; } else { ++total_right; } } total_len += n / 2; return dp[n - 1][0]; } int total_left = 0; int total_right = 0; int total_len = 0; };
code for problem3
#include <string> class ParenthesesDiv1Hard { public: int minCost(const std::string &s) { int len = static_cast<int>(s.size()); std::string red, blue; int r_num = 0, b_num = 0; for (int i = 0; i < len; ++i) { if (s[i] == '(') { if (r_num == b_num) { ++r_num; red += s[i]; } else { ++b_num; blue += s[i]; } } else { if (r_num > b_num) { red += s[i]; --r_num; } else if (b_num == 0) { return -1; } else { blue += s[i]; --b_num; } } } if (r_num != 0 || b_num != 0) { return -1; } return Score(red).second + Score(blue).second; } std::pair<int, int> Score(const std::string &s) { int left = 0; for (size_t i = 0; i < s.size(); ++i) { if (s[i] == '(') { ++left; } else if (--left == 0) { auto score1 = Score(s.substr(1, i - 1)); auto score2 = Score(s.substr(i + 1)); int depth = std::max(score1.first + 1, score2.first); int score = score1.second + (score1.first + 1) * (score1.first + 1) + score2.second; return {depth, score}; } } return {0, 0}; } };