难度hard
段式回文 其实与 一般回文 类似,只不过是最小的单位是 一段字符 而不是 单个字母。
举个例子,对于一般回文 "abcba" 是回文,而 "volvo" 不是,但如果我们把 "volvo" 分为 "vo"、"l"、"vo" 三段,则可以认为 “(vo)(l)(vo)” 是段式回文(分为 3 段)。
给你一个字符串 text,在确保它满足段式回文的前提下,请你返回 段 的 最大数量 k。
如果段的最大数量为 k,那么存在满足以下条件的 a_1, a_2, ..., a_k:
每个 a_i 都是一个非空字符串;
将这些字符串首位相连的结果 a_1 + a_2 + ... + a_k 和原始字符串 text 相同;
对于所有1 <= i <= k,都有 a_i = a_{k+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
解题思路:这道题可以说解题思路是相对直接的,没有那么难,就是用两个指针pre和cur指示左半部分应该截取的子字符串的两个坐标,同时用总字符串的长度减去这两个指针len-cur和len-pre用于指示右半部分应该截取的子字符串的坐标,然后将截出来的两段字符串进行比较,如果相等,那更新指针位置,pre=cur,同时更新结果res。注意不管两个字符串相等不相等,cur是一直在前进的,直到到达字符串中点,其实这本质上也是一种贪心策略,就是不断地尝试,一步步走,只要满足条件,就更新结果,把段数加上去。当退出while循环的时候,还需要再加一个操作,如果len是奇数,那说明中间肯定有一段字符串,没有被统计进来,因此结果应该加一,如果len是偶数,有两种情况:像"aaaa"这种,所有段数都被上一步囊括了,因此这种不做处理;另一种就是“aabcaa"这种,中间也有多的一个字符串,没有被上面的策略包括,这种情况下我们要在res中加一,此时只要判断pre指针是否小于len/2即可,因为前一种情况pre肯定能到达中点,而这种情况下则不行。
代码 t42 s60 java
class Solution {
public int longestDecomposition(String text) {
int res = 0, len = text.length(), pre = 0, cur = 1;
if(len==1) return 1;
while(cur<=len/2){
// System.out.println(text.substring(pre, cur));
// System.out.println(text.substring(len-cur, len-pre));
if(text.substring(pre, cur).equals(text.substring(len-cur, len-pre))){
res += 2;
pre = cur;
}
cur++;
}
if(len%2==1 || pre<len/2) res++;
return res;
}
}
下面有cpp的代码,思路差不多,供参考。
代码 t100 s70 cpp
class Solution {
public:
int longestDecomposition(string text) {
int sz = text.size(), pre = 0, res = 0;
for(int i=0; i<sz/2; i++){
if(text.substr(pre, i-pre+1)==text.substr(sz-i-1, i-pre+1)){
res += 2;
pre = i+1;
}
}
if(sz%2==1 || pre<sz/2) res++;
return res;
}
};
参考资料: