CF2069D. Palindrome Shuffle
D. Palindrome Shuffle
题意
给定长度为 \(n\) ( \(n\) 为偶数) 字符串 \(s\), 你可以选择 \(s\) 的一个子串 \(t\) 并且随意交换 \(t\) 中每个字符顺序使得 \(s\) 成为回文串. 求 \(t\) 的最小长度.
算法
双指针, 字符串.
思路
首先可以发现对于相同的前后缀, 我们可以直接去掉, 不会影响答案.
再来思考对于中间的子串, 如何选择子串才能够最小化长度?
先来考虑一种特殊情况: abb | abb
, 这种左右两部分字符集相等的情况只需要选择一侧进行交换即可成为回文串.
那么对于剩下的情况, 我们选择的子串会覆盖左右两侧的一部分, 现在问题是怎么选择子串长度最小. 现在考虑从左往右选. 对于每一个字符, 只要其在左侧的出现次数大于右边的出现次数就是合法的, 否则就需要更新区间. 注意这时左右两侧字符集是不相同的, 可能有的字符只在右侧出现过, 所以最后还需要在右侧更新一下右端点.
从右往左的操作是一样的, 将字符串翻转后再操作一次即可.
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
int deal() {
int l = INF, r = -INF;
for (int i = 1, t = 0, f = 0; i <= n >> 1; ++i) {
if (!cnt[s[i] - 'a']) ++t;
++cnt[s[i] - 'a'];
if (!cnt[s[i] - 'a']) --t;
if (!cnt[s[n - i + 1] - 'a']) ++t;
--cnt[s[n - i + 1] - 'a'];
if (!cnt[s[n - i + 1] - 'a']) --t;
if (t) l = min(l, i), f = 1;
else if (f) r = max(r, i), f = 0;
}
for (int i = n / 2 + 1; i <= n; ++i)
if (cnt[s[i] - 'a'] < 0) {
cnt[s[i] - 'a'] += 2;
r = i;
}
for (int i = 0; i < 26; ++i) cnt[i] = 0;
if (l == INF) return 0;
return r - l + 1;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步