classSolution { public: intminOperations(string word1, string word2){ int n = word1.size(); word1 = "0" + word1, word2 = "0" + word2; // cost[l][r]打表, 区间[l, r]的最小开销 int cost[105][105]; // cnt[x][y]:字母x需要找一个字母y进行交换 int cnt[26][26];
auto calc = [&](int i, int j, bool flag) -> int { int ans = 0; memset(cnt, 0, sizeof(cnt)); // 先处理交换的情况 for (int k = i; k <= j; ++k) { int x = word1[k] - 'a'; int y = flag ? word2[i + j - k] - 'a' : word2[k] - 'a'; if (x == y) continue; if (cnt[y][x]) cnt[y][x]--, ans += 1; else cnt[x][y]++; }
// 最后处理直接转换, 如果还有cnt[x][y]剩,说明x对y还有需求 for (int i = 0; i < 26; ++i) { for (int j = 0; j < 26; ++j) { if (cnt[i][j]) ans += cnt[i][j]; } } return ans; };
for (int i = 1; i <= n; ++i) { for (int j = i; j <= n; ++j) { cost[i][j] = min(calc(i, j, 0), calc(i, j, 1) + 1); } }
// DP int f[105]; memset(f, 0x3f, sizeof(f)); f[0] = 0; for (int i = 1; i <= n; ++i) { for (int j = i; j >= 1; --j) { f[i] = min(f[i], f[j - 1] + cost[j][i]); } } return f[n]; } };
尽管可以过,但是可以使用字符串的性质来进行优化到平方的复杂度
首先可以发现,DP是每次固定右端点,向左枚举左端点而遍历区间,而正序对比可以放一起做,道理很简单:
1 2 3
2 3 4 1 2 3 4 A B C --> 在前面新增一对需要对比的字母, x A B C D E F y D E F
可以发现,区间[2, 4]的转换已经结束了,完全可以使用它们的数据来更新[1, 4]
而反序对比不可以,道理也很显然:
1 2 3
2 3 4 1 2 3 4 C B A --> 在前面新增一对需要对比的字母, C B A x D E F y D E F
intminOperations(string word1, string word2){ int n = word1.size(); word1 = "0" + word1, word2 = "0" + word2;
int rev[105][105];
for (int i = 1; i <= n; ++i) { // 奇数中心 memset(cnt, 0, sizeof(cnt)); int tot = 1; int l = i, r = i; while (l >= 1 && r <= n) { int x = word1[l] - 'a', y = word2[r] - 'a'; if (x != y) { if (cnt[y][x]) cnt[y][x]--; else cnt[x][y]++, tot++; } if (l != r) { // ★ 只有长度>1时才处理第二对 x = word1[r] - 'a', y = word2[l] - 'a'; if (x != y) { if (cnt[y][x]) cnt[y][x]--; else cnt[x][y]++, tot++; } } rev[l][r] = tot; --l, ++r; }
// 偶数中心 if (i < n) { memset(cnt, 0, sizeof(cnt)); tot = 1; l = i, r = i + 1; while (l >= 1 && r <= n) { int x = word1[l] - 'a', y = word2[r] - 'a'; if (x != y) { if (cnt[y][x]) cnt[y][x]--; else cnt[x][y]++, tot++; } x = word1[r] - 'a', y = word2[l] - 'a'; if (x != y) { if (cnt[y][x]) cnt[y][x]--; else cnt[x][y]++, tot++; } rev[l][r] = tot; --l, ++r; } } }
// DP 正向 int f[105]; memset(f, 0x3f, sizeof(f)); f[0] = 0; for (int i = 1; i <= n; ++i) { memset(cnt, 0, sizeof(cnt)); int tot = 0; for (int j = i; j >= 1; --j) { int x = word1[j] - 'a', y = word2[j] - 'a'; if (x != y) { if (cnt[y][x]) cnt[y][x]--; else cnt[x][y]++, tot++; } f[i] = min(f[i], f[j - 1] + min(rev[j][i], tot)); } } return f[n]; } };