LeetCode 5

Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Soulution:

static const auto speedup = [](){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    string pre (string s){
        string t = "#";
        for (int i = 0; i < s.size(); i++){
            t += (s.substr(i,1) + "#");
        }
        return t;
    }

    string after (string s, int id, int num){
        int start = 0;
        if(num % 2 == 1){
            start = (id - 1) / 2 - (num / 2 - 1);
            num--;
        }else{
            start = id / 2 - (num / 2 - 1);
            num--;
        }
        return s.substr(start, num);
    }

    string longestPalindrome(string s) {
        if(s == "")return s;
        int mx = 0, center = 0, target_num = 0, target_id = 0;
        string t = s;
        s = pre(s);
        vector<int> P(s.size());
        P[0] = 1;
        for (int i = 1; i < s.size(); i++){
            P[i] = i < mx ? (P[2*center-i] < (mx - i) ? P[2*center-i] : (mx - i)) : 1;
            while(i + P[i] < s.size() && i - P[i] >= 0 && s[i+P[i]] == s[i-P[i]]){
                P[i]++;
            }
            if(i + P[i] > mx){
                center = i;
                mx = i + P[i];
            }
            if(P[i] > target_num){
                target_id = i;
                target_num = P[i];
            }
        }

        return after (t, target_id, target_num);
    }
};

1.基本思路

1.1 Manacher's Algorithm

简单来说这个算法是利用回文串镜像对称的特点,使在检测未探测到的回文串时,利用已知回文串的左半部分,尽可能地使得判断他右边的字符串的探测次数变少。从而达到O(n)的时间复杂度和O(n)的空间复杂度。

首先将要探测的字符串插入#字符(包含头尾),这是为了让你总能找到一个在数组中确实存在的对称中心,无论是奇数还是偶数个的字符串。

其中最核心的一行代码是

P[i] = i < mx ? (P[2*center-i] < (mx - i) ? P[2*center-i] : (mx - i)) : 1;

其中的变量如下:

P 存储该对称中心下回文字符串可以延伸的长度,P[i]-1为该长度

i 目前判断的index

mx 为当前延伸到最右端的回文串的最右端index,为的是尽可能大的利用回文串的镜像对称特性

center 为当前延伸到最右边的回文串的对称中心

所以对上面公式理解如下:

1 当i > mx时,意味着当前判断的字符串中心位置,已经超出之前可以延伸到最右端的回文串的最右端,这时候只能重新开始正常判断

2 当i <= mx时,就是当前判断的中心在字符串中,可以利用镜像对称的特性进行初始值的设定

2.1  (P[2*center-i] < (mx - i) ? P[2*center-i] : (mx - i)) 这里的P[2*center-i]是与当前中心沿着Center对称的中心字符串的最长回文串长度,当时如果超过了中心回文串右边界的长度mx-i,那么大于mx-i的部分就没有意义了,因为在这一部分无法利用镜像对称对P进行初始化

3 当i+P[i]>mx时,即当前回文串的最右端超过上一个回文串的最右端,那么更新参数center和mx,使得我们可以充分利用镜像的特性

4 同时对比当前的最大长度,实时更新最大长度和它对应的index

1.2 动态规划 DP

const int maxn = 1010;
char a[maxn];
int dp[maxn][maxn];
int len = 0, ans = 1;

void init()
    memset(dp, 0, sizeof(dp));
    for(int i = 0; i < len; ++i){
        dp[i][i] = 1;
        if(i < len - 1){
            int j = i + 1;
            if(a[i] == a[j]){
                dp[i][j] = 1;
                ans = 2;
            }
        }
    }
} 

void DP(){

    init();

    for(int l = 3; l < len; ++l){
        for(int i = 0; i + l - 1 < len; ++i){
            int j = i + l - 1;
            if(a[i] == a[j] && dp[i + 1][j - 1] == 1){
                dp[i][j] = 1;
                ans = l;
            }
        }
    }
} 

 

posted @ 2018-09-06 13:26  一只狐狸scse  阅读(156)  评论(0编辑  收藏  举报