leetcode (5) - Longest Palindromic Substring 最长回文子串

  • 问题描述

    回文串是指这个字符串无论从左读还是从右读,所读的顺序是一样的;简而言之,回文串是左右对称的。现在,对于一个给定的母串

    abcdedcb

    可以找出子串a, ded, cdedc, bcdecdb等均是回文串;显然,bcdecdb是其中最长的那一个。但是该如何找出最长的回文子串呢?

    问题解法

    最容易想到的依然是穷举法,穷举所有子串,找出是回文串的子串,统计出最长的那一个。

    穷举法

    i, j的for循环表示字符串s[i..j],然后逐一判断,找出最长。

    /*判断str[i..j]是否为回文串*/
    int isPalindrome(char *str, int begin, int end) {
        while(str[begin] == str[end] && begin <= end) {
            begin++;
            end--;
        }
        if(str[begin] != str[end]) {
            return 0;
        } else {
            return 1;
        }
    }
    
    /*返回最长回文子串长度*/
    int longestPald(char *str) {
        int len = strlen(str);
        int i, j;
        int longest = 1;
        assert(str != NULL);
        if(len == 1) {
            return 1;
        }
    
        for(i = 0; i<len; i++) {
            for(j=i+1; j<len; j++) {
                if(isPalindrome(str, i, j)) {
                    longest = (longest < j-i+1 ? j-i+1: longest);
                }
            }   
        }
        return longest;
    }

    穷举法的时间复杂度为 O(n3) ,复杂度太高了,需要做一些改进。

========  自己的做法: leetcode无法提交,时间复杂度太高了,总提示 time limit exceeded,  ============


bool is_max_sub(char *s, int start, int end) {
    if (start > end) return false;
    if (start == end) return true;
    while (start < end && s[start] == s[end]) {
        start++;
        end--;
    }
    if (start >= end) 
        return true;
    else
        return false;
}


char* longestPalindrome(char* s) {
    int max_length=0;
    int length=strlen(s);
    int start, end, max_start, max_end;
    for (start=0; start<length; start++) {
        for(end=start; end<length; end++) {
            
            if (is_max_sub(s, start, end)) {
              
                if (max_length < (end-start+1)) {
                    max_length=end-start+1;
                    max_start=start;
                    max_end=end;
                }
            }
        }
    }
    int i=0;
    char * max_sub = malloc(sizeof(char) * (max_length+1));
    for ( i =0; i<max_length; i++){
        max_sub[i] = s[max_start];
        max_start++;
    }
    max_sub[max_length]='\0';
    return max_sub;
}



========  自己的做法  ============


  • 对穷举法的改进

    回文串是左右对称的,如果从中心轴开始遍历,会减少一层循环。思路:依次以母串的每一个字符为中心轴,得到回文串;然后通过比较得到最长的那一个。注意:要考虑到像baccab这样的特殊子串,可以理解它的中心轴是cc。

    /*以mid为中心轴的回文子串*/
    int l2r(char *str, int mid) {
        int l = mid -1, r = mid+1;
        int len = strlen(str);
        while(str[r] == str[mid]) {
            r++;
        }
        while(l >= 0 && r < len && str[l] == str[r]) {
            l--;
            r++;
        }
        return r-l-1;
    }
    
    int longestPald(char *str) {
        int len = strlen(str);
        int i;
        int longest = 1;
        assert(str != NULL);
        if(len == 1) {
            return 1;
        }
    
        for(i = 0; i<len; i++) {
            if(l2r(str, i) > longest)
                longest = l2r(str, i);
        }
    
        return longest;
    }
    • 时间复杂度: O(n2)
  • .
  • 空间复杂度: O(1)
    • .

    动态规划

    有母串s,我们用c[i, j] = 1表示子串s[i..j]为回文子串,那么就有递推式

    c[i,j]={c[i+1,j1]0if s[i]=s[j]if s[i]s[j]

    递推式表示在s[i] = s[j]情况下,如果s[i+1..j-1]是回文子串,则s[i..j]也是回文子串;如果s[i+1..j-1]不是回文子串,则s[i..j]也不是回文子串。

    初始状态:

    • c[i][i] = 1
    • c[i][i+1] = 1 if s[i] == s[i+1]

    上述式子表示单个字符、两个字符均是回文串。

    int longestPald(char *str) {
        int len = strlen(str);
        int c[maxLen][maxLen];
        int i,j;
        int longest = 1;
        
        assert(str != NULL);
        if(len == 1) {
            return 1;
        }
          //initialization
        for(i = 0; i < len; i++) {
            c[i][i] = 1;
                    if(str[i] == str[i+1])
               c[i][i+1] = 1;
        }
    
        for(i = 0; i < len; i++) {
            for(j = i+2; j <= len; j++) {
                if(str[i] == str[j]) {
                    c[i][j] = c[i+1][j-1];
                    //find longest palindrome substring
                    if(c[i][j]) { 
                        int n = j - i + 1;
                        if(longest < n)
                            longest = n;                
                    }
                } else {
                    c[i][j] = 0;
                }
            }
        }
        return longest;
    }
    • 时间复杂度: O(n2)
  • .
  • 空间复杂度: O(n2) .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值