[1147].段式回文
Posted Debroon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[1147].段式回文相关的知识,希望对你有一定的参考价值。
题目
[1147].段式回文:https://leetcode-cn.com/problems/longest-chunked-palindrome-decomposition/
比如 volvo
如果按照 3 段切分就是一个回文 (vo) (l) (vo),分成 5 段就不是回文,请问最大可以分成几段?
函数原型
int longestDecomposition(string text)
贪心 + 哈希优化
一个回文单词拆解的结构:
那我们从俩端开始,左边第一个字母 == 右边第一个字母?
俩种情况:
-
如果相同,就是一段回文,那继续按照这个思路看左边第二个字母 == 右边第二个字母。
-
通常,不会相等,如
volvo
左、右边第一个字母就不同 ,但只需要在延展一个字母就相同了。左边下标往左推一个、右边下标往右推一个,再看字母组合是否匹配。
class Solution
public:
int longestDecomposition(string text)
return Recursion( text, 0, text.length()-1 );
int Recursion(string s, int left, int right)
if( left > right ) // 空串
return 0;
for( int i = left, j = right; i < j; i++, j--)
if( equals(s, left, i, j, right) ) // s[left, i] == s[j, right]?
return 2 + Recursion(s, i + 1, j - 1); // 找到 2 段
return 1; // 不能分段
bool equals(string s, int l1, int r1, int l2, int r2)
for(int i=l1, j=l2; i<=r1 && j<=r2; i++, j++) // s[l1, r1] == s[l2, r2]?
if(s[i] != s[j]) // s[i] == s[j]?
return false;
return true;
;
更简洁的写法:
- 前 i 个字符只要和后i个字符完全一致即视为匹配成功,每次递归中,只要有一次匹配成功即退出循环。
class Solution
public:
int longestDecomposition(string text)
for(int i = 1; i <= text.length()/2; ++i)
if(text.substr(0, i) == text.substr(text.length()-i, i))
return 2 + longestDecomposition(text.substr(i, text.length() - i*2));
return text.length()>0 ? 1:0;
;
不过,字符串匹配的过程需要 O ( n ) O(n) O(n),我们可以用哈希,把字符串匹配变成整数匹配,只需要 O ( 1 ) O(1) O(1)。
- 左边: 当 前 字 母 ∗ 10 + 新 字 母 当前字母 * 10 + 新字母 当前字母∗10+新字母,如 123 ∗ 10 + 4 = 1234 123 * 10 + 4 = 1234 123∗10+4=1234
- 右边: 新 字 母 ∗ 1 0 l e n − 1 + 当 前 字 母 新字母 * 10^len-1 + 当前字母 新字母∗10len−1+当前字母,如 4 ∗ 1 0 3 + 123 = 4123 4*10^3+123=4123 4∗103+123=4123
比如 volvo
,左边是 v
、vo
,右边是 o
、vo
(不是 ov
)。
if( equals(s, left, i, j, right) ) // s[left, i] == s[j, right]?
所以,在俩个子串判等的时候,使用哈希优化。
class Solution
long MOD = (long)(1e9 + 7); // 素数,防止溢出
long pow26[];
public:
int longestDecomposition(string text)
return Recursion( text, 0, text.length()-1 );
int Recursion(string s, int left, int right)
if( left > right ) // 空串
return 0;
long left_hash = 0, right_hash = 0; // 记录左右哈希值
long *pow26 = new long[s.length()]; // 提前计算26的幂
pow26[0] = 1;
for(int i=1; i<s.length(); i++)
pow26[i] = pow26[i - 1] *26 % MOD; // 防止溢出
for( int i = left, j = right; i < j; i++, j--)
left_hash = (left_hash * 26 + (s[i] - 'a')) % MOD; // 采用 26 进制,a 对应 0
right_hash = ((s[j] - 'a') * pow26[right - j] + right_hash) % MOD;
if( left_hash == right_hash && equals(s, left, i, j, right) ) // s[left, i] == s[j, right]?
return 2 + Recursion(s, i + 1, j - 1); // 找到 2 段
return 1; // 不能分段
bool equals(string s, int l1, int r1, int l2, int r2)
for(int i=l1, j=l2; i<=r1 && j<=r2; i++, j++) // s[l1, r1] == s[l2, r2]?
if(s[i] != s[j]) // s[i] == s[j]?
return false;
return true;
;
动态规划
思路:如果给定字符串可以分解为 APA 形式,P为中间任意长度字串,则 APA 的段最大数量是 P 的段数量 + 2。
class Solution
public:
int longestDecomposition(string text)
int m = text.length();
vector<int> dp((m+1)/2,1);
if(m&1)
dp.back() = 1;
int p = m/2-1;
int q = (m+1)/2;
for(int i =p;i>=0;i--)
for(int j = i;j<=p;j++)
if(text.substr(i,j-i+1)==text.substr(q+p-j,j-i+1))
dp[i] = max(dp[i], j+1>=dp.size() ? 2:dp[j+1]+2);
if(dp[0]<0)
return 1;
return dp[0];
;
以上是关于[1147].段式回文的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode-5150 Longest Chunked Palindrome Decomposition(段式回文)
C 语言中 Mainframe TN3270(代码页 1047,1147,500,249)上的字符串/正则表达式字符 '[', ']', '', '' 替换为空格