Skip to content
本页目录

0214-最短回文串

https://leetcode.cn/problems/shortest-palindrome

给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

示例 1:

输入:s = "aacecaaa"
输出:"aaacecaaa"

示例 2:

输入:s = "abcd"
输出:"dcbabcd"

提示:

0 <= s.length <= 5 * 104
s 仅由小写英文字母组成

思路1 【官方 KMP】

首先我们可以肯定,对字符串 s 去掉第一个字符,将后面的 s[1..n] 反序添加到前面,就可以得到回文串 而题目要找的数字串长度肯定小于等于这个长度,即 s'.Length <= s.Length -1 那么具体可以小多少呢,我们如果从 s[0] 开始找出s[0]开始的最大的回文串,那么剩下的部分,反序之后,就是要添加的字符串。 详情:参考题解 https://leetcode.cn/problems/shortest-palindrome/solution/zui-duan-hui-wen-chuan-by-leetcode-solution/

比较字符串的算法可以使用KMP算法:

将源字符串添加 # 和 反序 s', 计算最后的公共前后缀即为最大回文的长度 如 aacecaaa#aaacecaa 最大的公共前后缀就是 aa 为2 那么添加的数就是 s[2-1,length] 反序

添加 # 的原因是, 如果重复的字符串如 aaa 直接添加 aaa后 aaaaaa 计算的结果是 6 但是实际需要的是 3 ,所以 aaa#aaa 得出的是正确的结果。

参考代码

csharp
public class Solution {
    public string ShortestPalindrome(string s) {
    	string str = s+"#";
    	for(int i=s.Length-1;i>=0;i--){
    		str+=s[i];
    	}
    	//计算 kmp next 数组
    	int prefixIndex = 0;
    	int[] next = new int[str.Length];
    	next[0] = 0;
    	for(int nextIndex = 1; nextIndex < str.Length; nextIndex++){
    		while(prefixIndex > 0 && str[prefixIndex] != str[nextIndex] ){
    			prefixIndex = next[prefixIndex-1];
    		}
    		if(str[prefixIndex] == str[nextIndex]){
    			prefixIndex++;
    			next[nextIndex] = prefixIndex;
    		}
    	}
    	int index = next[str.Length-1];

        //打印 next 数组
        // Console.WriteLine(str);
        // for(int i=0; i<next.Length; i++){
        //     Console.Write("{0}",next[i]);
        // }

    	string result = "";
    	for(int i=s.Length-1; i>=index; i--){
    		result+=s[i];
    	}
        result += s;

    	return result;
    }
}

思路:复习20220520

输入:s = "aacecaaa"
输出:"aaacecaaa"

题目要求在最前面增加字符串变成回文串。

  1. 首先考虑最大解,我们将数字反序追加到前面,这样肯定是回文串,比如 ananab 变成 banana+ananab,增加一个加号为了便于说明
  2. 然后我们考虑第一个字符肯定是回文的,所以不需要转换第一个字符 则变成 banan+a+nanab
  3. 但实际上中间有 anana 就是回文的,所以实际上我们只要复制一个b b+anana+b
  4. 现在问题就是如何找到 anana 这个最小的回文串
  5. 我们可以通过在原来字符后面增加一个 # 号,然后将字符串反转追加,有 ananab#banana ,因为是回文的,所以他翻转的也是一样的字符,所以问题变成找到公共前后缀的方式
  6. 我们可以使用 KMP 算法中求解 next 数组的方式来求取公共前后缀
csharp
public class Solution {
    public string ShortestPalindrome(string s) {
        string str = s+"#";
        for(int i = s.Length-1;i>=0;i--){
            str+=s[i];
        }
        //求取next数组 ananabanana , aabaabaaf
        int j = 0; 
        int[] next = new int[str.Length];
        for(int k = 1; k<str.Length; k++){
            //不匹配
            while(str[k] != str[j] && j != 0){
                j = next[j-1];
            }
            //匹配
            if(str[k] == str[j]){
                j++;
                next[k] = j;
            }
        }
        int index = next[str.Length-1]; //最后的公共前后缀长度
        //Console.WriteLine("index={0}",index);

        string result = "";

        for(int k=s.Length-1;k>=index; k--){
            result+=s[k];
        }
        result+=s;
        return result;
    }
}

复习:20220705

差不多是抄出来的,kmp还需加强

csharp
public class Solution {
    public string ShortestPalindrome(string s) {
        //第1步:拼接字符串为 abcde#ebcda的格式
        string str = s + "#";
        for(int i=s.Length-1; i>=0; i--){
            str+=s[i];
        }
        //第2步:求公共前后缀的数组长度 KMP next 数组
        int[] next = new int[str.Length];
        //从第1个开始求
        int j=0;
        for(int i=1; i<str.Length; i++){
            while(j != 0 && str[i] != str[j]){
                j = next[j-1];
            }
            if(str[i] == str[j]){
                j++;
                next[i] = j;
            }
        }
        //找出 index,即为公共前后缀,把剩余部分反向加入进去
        int index = next[str.Length-1];
        string result = "";
        for(int i=s.Length-1; i>=index;i--){
            result += s[i];
        }
        result+=s;
        return result;
    }
}

Released under the MIT License.