贪心 - 段式回文 - Leetcode 1147
段式回文 其实与 一般回文 类似,只不过是最小的单位是 一段字符 而不是 单个字母。
举个例子,对于一般回文 “abcba” 是回文,而 “volvo” 不是,但如果我们把 “volvo” 分为 “vo”、“l”、“vo” 三段,则可以认为 “(vo)(l)(vo)” 是段式回文(分为 3 段)。
给你一个字符串 text,在确保它满足段式回文的前提下,请你返回 段 的 最大数量 k。
如果段的最大数量为 k,那么存在满足以下条件的 a1, a2, …, ak:
- 每个 a_i 都是一个非空字符串;
- 将这些字符串首位相连的结果 a1 + a2 + … + ak 和原始字符串 text 相同;
- 对于所有1 <= i <= k,都有 ai = ak+1-i。
示例 1:
输入:text = "ghiabcdefhelloadamhelloabcdefghi"
输出:7
解释:我们可以把字符串拆分成 "(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)"。
示例 2:
输入:text = "merchant"
输出:1
解释:我们可以把字符串拆分成 "(merchant)"。
示例 3:
输入:text = "antaprezatepzapreanta"
输出:11
解释:我们可以把字符串拆分成 "(a)(nt)(a)(pre)(za)(tpe)(za)(pre)(a)(nt)(a)"。
示例 4:
输入:text = "aaa"
输出:3
解释:我们可以把字符串拆分成 "(a)(a)(a)"。
提示:
text 仅由小写英文字符组成。
1 <= text.length <= 1000
分析:
策略: 从左至右扫描,优先选择最短的“段”进行匹配。(思考:这样是不是能够匹配最多的段?有没有可能前面匹配的段不是最短的,可以使得后面匹配的段更多?)
证明:
对于字符串 s [ 1 : n ] s[1:n] s[1:n],我们假设最左端(最短)的一个匹配的段在位置 p 1 p_1 p1,即 s [ 1 : p 1 ] = s [ n − p 1 + 1 : n ] 。 s[1:p_1]=s[n-p_1+1:n]。 s[1:p1]=s[n−p1+1:n]。
假设我们在 p 1 p_1 p1 处不进行匹配,而在 p 2 p_2 p2 处匹配,即 s [ 1 : p 2 ] = s [ n − p 2 + 1 : n ] 。 s[1:p_2]=s[n-p_2+1:n]。 s[1:p2]=s[n−p2+1:n]。
可以得到, s [ p 2 − p 1 + 1 : p 2 ] = s [ n − p 1 + 1 : n ] = s [ 1 : p 1 ] s[p_2-p_1+1:p_2]=s[n-p_1+1:n]=s[1:p_1] s[p2−p1+1:p2]=s[n−p1+1:n]=s[1:p1]
进而得到, s [ 1 : p 2 − p 1 + 1 ] = s [ p 1 : p 2 ] s[1:p_2-p_1+1]=s[p_1:p_2] s[1:p2−p1+1]=s[p1:p2],即红色段拥有一个长度为 L c o m = p 2 − p 1 + 1 L_{com}=p_2-p_1+1 Lcom=p2−p1+1 相同前缀和后缀。
因此, s [ 1 : L c o m ] = s [ n − L c o m + 1 : n ] s[1:L_{com}]=s[n-L_{com}+1:n] s[1:Lcom]=s[n−Lcom+1:n]。
这就与我们的假设:最左端的匹配段的位置是 p 1 p_1 p1 矛盾了。最左端的匹配的位置应该在 L c o m L_{com} Lcom 处。
所以我们应该每次匹配最短的段。
代码:
class Solution {
public:
int calc(string& text, int l, int r)
{
int n = text.size();
string a, b;
for(int k = 1; k <= n >> 1; k ++)
{
a = text.substr(l, k);
b = text.substr(r - k + 1, k);
if(a == b) return k;
}
return 1000;
}
int longestDecomposition(string text)
{
int n = text.size();
int ans = 0;
int l = 0, r = n - 1;
while(l <= r)
{
int k = calc(text, l, r);
if(l + k - 1 < r - k + 1) ans += 2;
else ++ ans;
l += k;
r -= k;
}
return ans;
}
};