214-最短回文

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LaputaFallen/article/details/79966549

Description

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.


For example:

Given "aacecaaa", return "aaacecaaa".

Given "abcd", return "dcbabcd".

问题描述

给定字符串S,你允许向S的前端添加任意字符以使S称为回文串
找出通过这种转换可以获得的最短的回文串


问题分析

两种做法,递归和KMP,核心都是找出最长前缀回文

做法1, 递归

可以通过维护两个指针i和j来找出最长前缀回文的范围
j = length - 1,i = 0,通过j从右往左遍历字符串。若s.charAt(i) == s.charAt(j),那么i++.
来看一个例子
s = “aacecaaa”,i = 0, j = 7
可以自己在草稿纸上演算一下,最终会得到i = 7,最长前缀回文一定在[0, i - 1]的范围内,那么我们就可以将
s进行分解,由于[i, length - 1]一定不是回文,那么我们必须得将这部分字符串逆序添加到头部,
剩余部分由递归[0, i - 1] (注意,若递归时s为回文,那么直接返回)加上字符串的[i, length - 1]部分构成

做法2,KMP

对于KMP,思想是一样的,还是找出最长前缀回文
我们先将s逆序,得到rev,构成新的字符串new_s = s + “#” + rev(注意这里的”#”,为了防止混合字符串s和rev导致前缀计算错误),那么问题就转化为了得出最长前缀后缀字符串,于是我们可以通过KMP的lps( longest proper prefix which is also suffix)数组求解
如果不熟悉KMP的话,可以看看这个链接
https://www.geeksforgeeks.org/searching-for-patterns-set-2-kmp-algorithm/


解法1(递归)

class Solution {
    public String shortestPalindrome(String s) {
        int i = 0, n = s.length();

        for(int j = n - 1;j >= 0;j--){
            if(s.charAt(i) == s.charAt(j))  i++;
        }
        //若i == n那么s为回文,直接返回
        if(i == n) return s;

        String remain = new StringBuilder(s.substring(i, n)).reverse().toString();

        //remain一定不是回文,直接加上,注意尾部也要添加s的尾部
        //最长前缀回文一定在s.substring(0, i)(注意是在,而不是就是s.substring(0, i))
        return remain + shortestPalindrome(s.substring(0, i)) + s.substring(i, n);
    }
}

解法2(KMP)

class Solution {
    public String shortestPalindrome(String s) {
        int n = s.length();
        String rev = new StringBuilder(s).reverse().toString();
        String s_new = s + "#" + rev;
        int n_new = s_new.length();
        int[] lps = new int[n_new];

        for(int i = 1;i < n_new;i++){
            int t = lps[i - 1];
            while(t > 0 && s_new.charAt(i) != s_new.charAt(t))  t = lps[t - 1];
            if(s_new.charAt(i) == s_new.charAt(t))  ++t;
            lps[i] = t;
        }
        //由于lps[n_new - 1]为最长前缀回文串的长度,那么将其减去得到不是回文串的长度
        //即rev.substring(0, n - lps[n_new - 1])为非回文串,将其添加在前端即可
        return rev.substring(0, n - lps[n_new - 1]) + s;
    }
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页