Shortest Palindrome ---再见回文和KMP

来源:互联网 发布:淘宝消保30元加入条件 编辑:程序博客网 时间:2024/05/18 11:19

题目大意

    给定串S,要求在其前面(in front of)增加最少的串构成回文并输出回文串。

解题思路

     席八,这个题目无愧其hard的标签,我想破脑袋也才想了个宽搜的暴力,而且还忽略了要加载S串前面的基本要求,审题不仔细,还是太浮躁了。这题没做出来,仔细琢磨了网上的解法,现总结如下:

    先明确几个理论,以后想回文相关的题目从这几点入手:

                                      1、回文串 = reverse(回文串)

                                      2、回文串T+回文串T 为了减少长度可以压缩视为为一个回文串T

                                      3、任何字符串S 经过镜面翻转必为回文串

   以上三点看上去都特么是废话,但就是这种简单的常识往往难以被重视。回到这个题目,首先尝试构造一个最坏的解,根据第三点,将S串翻转,加到其前(为什么不是后面?因为题目要求要在前面加嘛。。。众人:碧池~~)。这样显然用最差的方式构建了一个长度为2*s.length()的回文串,因此需要对其进行优化,此时考虑上述第二点,如果S前缀和后缀都是回文串的话,这样翻转之后的串就能够被压缩了。。注意这里出现了前缀和后缀,前缀和后缀,前缀和后缀,重要的事情讲三遍,是的,前缀和后缀(众人:还来?滚粗!说重点),由此很是不是很容易想到通过KMP的next串的构造找到前缀和后缀相同的长度?因此重新构造字符串T=原串S,将T镜面翻转到后面构成T’(为什么这次翻转到后面,因为需要检测S前缀中回文长度,根据第一点,利用KMP匹配出来的前缀肯定是回文),这样通过KMP可以得出其前缀最长回文长度,最后只需要将原串中非回文的部分(长度为s.length()-next[T‘.length()-1])的部分翻转到串的最前面就可以满足题目的要求了,整体来讲应该是一种贪心的思路。

补充:

这里有个细节需要更正一下,首先感谢田神要努力填坑同志能发现这一问题,并给出合适的测试样例aabba。该算法存在一个细节问题,执行KMP匹配的时候不应当进行重复的匹配,这样会导致判断前缀回文的判断超过串本身的长度(因为是直接翻转后放置在后面,故而计算next数组时会将翻转串的部分也会比对进来),因此应当将翻转串和原串分开比对,略作修改就好

总结

    首先题目要看懂,其次但凡涉及回文就要考虑上述三点基本特征

代码(存在问题)

class Solution {int next[81000];void generateNext(string s){  next[0]  = 0;          for (int i = 1, j = 0; i < s.length(); i ++) {       while (j > 0 && s[j] != s[i])  j = next[j-1];                if (s[i] == s[j])  j ++;               next[i] = j;          }}public:    string shortestPalindrome(string s) {int sLen = s.length();if (sLen == 0)return "";string cur = s;string rs = s;reverse(rs.begin(), rs.end());cur += rs;int curN = cur.length();                generateNext(cur);                int commonLen = next[curN-1];if (commonLen > sLen)return s;string res = s.substr(commonLen,sLen-commonLen);reverse(res.begin(), res.end());return (res+s);    }};

代码(修改上段代码的错误)

<span style="font-size:14px;">class Solution {      int next1[41000];int next2[41000];    void generateNext(string s1, string s2)      {            next1[0] = 0;  next2[0] = 0;            int len1 = s1.length();          for (int i = 1, j = 0; i < len1; i ++) {                while (j > 0 && s1[j] != s1[i])  j = next1[j-1];                  if (s1[i] == s1[j])  j ++;                 next1[i] = j;            }  //这里使用翻转串s2去匹配原串s1          for (int i = 0, j = 0; i < len1; i ++) {                 while (j > 0 && s2[i] != s1[j])  j = next1[j-1];                  if (s2[i] == s1[j])  j ++;                 next2[i] = j;            }      }  public:      string shortestPalindrome(string s) {          int sLen = s.length();          if (sLen == 0)return "";          string cur = s;          string rs = s;          reverse(rs.begin(), rs.end());          //cur += rs;          int curN = cur.length();          generateNext(cur, rs);          int commonLen = next2[curN-1];          if (commonLen > sLen)return s;          string res = s.substr(commonLen,sLen-commonLen);          reverse(res.begin(), res.end());        return (res+s);      }  }; </span>



0 0
原创粉丝点击