leetcode 214. Shortest Palindrome

这道题的意思是往字符串前面添加字串,使得整个字符串是回文串;

第一种方法:

既然是回文串,那么最先想到的是最长回文子串。最长回文子串的pat是pat[index] 代表以index为中点左右两边最长的回文串。

那么如果pat[index] == index说明从起始点到该点再加上index是回文串的。那么我们只要找到这样的一个最大的pat[index]即可。

复制代码
class Solution {
    public:
    string shortestPalindrome(string s) {
        if (s.length() <= 1)
            return s;
        
        string ss = initS(s);
        vector<int> pat = initCalc(ss);
        int min_len = s.length() - 1;
        for (int i = 1; i < (ss.length()+1)/2; ++i) {
            if (pat[i] == i) {
                int len = (ss.length() - i * 2 - 1) / 2;
                min_len = min_len < len?min_len : len;
            }
        }
        
        string result;
        for (int i = 0; i < min_len; ++i) {
            result.push_back(s[s.length() - i - 1]);
        }
        result += s;
        
        return result;
    }
    
    string initS(const string& s) {
        string result(s.length() * 2 + 1, '#');
        
        for (int i = 0; i < s.length(); ++i)
            result[i * 2 + 1] = s[i];
        
        return result;
    }
    
    vector<int> initCalc(const string& ss) {
        vector<int> result(ss.length(), 0);
        
        int max_right = 0;
        int max_middle = 0;
        for (int i = 1; i < ss.length(); ++i) {
            if (i < max_right) {
                int left_pos = max_middle * 2 - i;
                result[i] = result[left_pos];
                if (result[i] + i > max_right)
                    result[i] = max_right - i;
            }
            int pos = i + result[i] + 1;
            while (pos < ss.length() && pos <= i * 2 && ss[pos] == ss[i*2-pos])
                ++pos;
            result[i] = pos - i - 1;
            if (pos - 1 > max_right) {
                max_right = pos - 1;
                max_middle = i;
            }
        }
        
        return result;
    }
};
复制代码

如上先求出pat,然后再找最长子串。

 

 

第二种方法:

既然是子串,并且是从最开始的字符串开始匹配的。那么跟kmp里面的计算next很相似:next是计算跟起始字符相同的子串的长度。比如:abc.....abc; next= 000......123

那么我们如果有这么一个字符串:abc,我们将它构造成 abc#cba  那么next.back()的长度就是从a开始的最长回文子串;

所以计算的过程即为求next的过程。

复制代码
        string shortestPalindrome(string s) {
            if(s.size()<=1)
                return s;
            
            string r = s;
            reverse(r.begin(), r.end());
            r = s + "#" + r;
            vector<int> next(r.length(), 0);
            for (int i = 1; i < next.size(); ++i) {
                int j = next[i-1];
                while (j > 0 && r[j] != r[i])
                    j = next[j-1];
                next[i] = j + (r[i] == r[j]?1:0);
            }
            string temp = s.substr(next.back());
            reverse(temp.begin(), temp.end());
            
            return temp + s;
        }
复制代码

 

如上两种算法的效率差不多都是一样的O(n),但是第二种算法的计算过程比第一种算法简单的多。

posted @   LCAC  阅读(125)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示