[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 12310+4=1234
  • 右边: 新 字 母 ∗ 1 0 l e n − 1 + 当 前 字 母 新字母 * 10^len-1 + 当前字母 10len1+,如 4 ∗ 1 0 3 + 123 = 4123 4*10^3+123=4123 4103+123=4123

比如 volvo ,左边是 vvo ,右边是 ovo(不是 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].段式回文的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode1147 段式回文

Leetcode-5150 Longest Chunked Palindrome Decomposition(段式回文)

模式匹配:滚动哈希到 Rabin-Karp 算法

模式匹配:滚动哈希到 Rabin-Karp 算法

C 语言中 Mainframe TN3270(代码页 1047,1147,500,249)上的字符串/正则表达式字符 '[', ']', '', '' 替换为空格

OJ1147括号匹配加强版(栈)