最长回文子串

1、问题描述

给定一个字符串 s,找到 s 中最长的回文子串。

2、算法分析

大多数问题都可以用暴力法解决。暴力法将选出所有子字符串可能的开始和结束位置,并检验它是不是回文。

  • 时间复杂度:O(n3),假设 n 是输入字符串的长度,则 (n * (n−1))/2​ 为此类子字符串(不包括字符本身是回文的一般解法)的总数。因为验证每个子字符串需要 O(n) 的时间,所以运行时间复杂度是 O(n3)。

  • 空间复杂度:O(1)。 

为了改进暴力法,我们首先观察如何避免在验证回文时进行不必要的重复计算。考虑 "ababa" 这个示例。如果我们已经知道 "bab" 是回文,那么很明显,"ababa" 一定是回文,因为它的左首字母和右尾字母是相同的。

我们给出 P(i,j) 的定义如下:

如果子串 Si...Sj ​是回文子串   p(i, j) = true

其他情况                   p(i, j) = false

因此:

P(i, j) = ( P(i+1, j-1) and Si​ == Sj​)

基本示例如下:

P(i, i) = true

P(i, i+1) = (Si ​== Si+1​)

这产生了一个直观的动态规划解法,我们首先初始化一字母和二字母的回文,然后找到所有三字母回文,并依此类推…

3、复杂度分析

  • 时间复杂度:O(n2),这里给出我们的运行时间复杂度为 O(n2)。

  • 空间复杂度:O(n2),该方法使用 O(n2) 的空间来存储表。

4、代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * longestPalindrome(char* s)
{
    if (s == NULL || strlen(s) < 1) {
        return "";
    }
    int n = (int)strlen(s);
    
    // 初始化二维数组
    int matrix[n][n];
    for (int i = 0; i < n; i++)
        for (int j = 0; j< n; j++)
            matrix[i][j] = 0;
    
    int left  = 0;
    int right = 0;
    
    // i 从倒数第二个开始,从右往左。标识子串的起始位置
    for (int i = n - 2; i >= 0; i--) {
        
        matrix[i][i] = 1;
        
        // j 从 i 的下一位开始,从左往右。标识子串的结束位置
        for (int j = i + 1; j < n; j++) {
            
            // ①、s[i] == s[j]     ②、小于或等于 3 个字符     ③、内缩一位是回文子串
            matrix[i][j] = (s[i] == s[j] && (j - i < 3 || matrix[i+1][j-1]));
            
            // 获得最长的子串位置
            if(matrix[i][j] && right - left < j - i) {
                left  = i;
                right = j;
            }
            
            for (int m = 0; m < n; m++) {
                for (int k = 0; k < n; k++)
                    printf("%d   ", matrix[m][k]);
                printf("\n\n");
            }
        }
    }
    
    char* sub = (char *)malloc(sizeof(char) * (right - left + 1));
    int i = 0;
    for (; i < right - left + 1; i++) {
        sub[i] = s[left + i];  //strncpy(sub, s+left, right+1);
    }
    sub[i] = '\0';
    
    return sub;
}

int main()
{
    printf("%s", longestPalindrome("aaabaaaa"));
    
    return 0;
}

关键代码:

matrix[i][j] = (s[i] == s[j] && (j - i < 3 || matrix[i+1][j-1])); 以及 i 和 j 的取值方向

posted @ 2020-03-15 13:35  和风细羽  阅读(163)  评论(0编辑  收藏  举报