zoukankan      html  css  js  c++  java
  • 5. Longest Palindromic Substring【字符串 DP】

    Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
     

    版本1:Brute Force    O(n^3)

    双指针
    ——————————————————————————————————
    版本2:DP---改进版本1,避免重复计算    O(n^2)   | O(n^2) 
     
    该方法可以用于收集整个字符串的回文状态,作为子问题。
    类似于LCS,是LCS与KMP的变种,若采用LCS是有问题的,因为公共子串未必是回文串
     
    解:

    状态:定义二维数组P[i,j]用以表示Si…Sj是回文(true)或不是回文(false)

    状态转移方程 : P[i,j] = (P[i + 1, j - 1] && Si ==Sj)

    初始条件是:P[i, i]=true,P[i, i + 1] = (Si == Si+1)

    C++版( 使用 C++ 、java可以A , Python超时

     

    class Solution {
    public:
        string longestPalindrome(string s) {
        	int l = s.length();
        	bool p[1000][1000] = {false};
        	int max_len = 1 , max_beg = 0;
        	p[l-1][l-1] = true;
        	for(int i=0;i<l;i++){
        		p[i][i] = true;
        		if(s[i] == s[i+1]){
        			p[i][i+1] = true;
        			max_len = 2;
        			max_beg = i;
        		}
        	}
        	for(int length=3 ;length<=l ;length++){
        		for(int i=0;i<=l-length;i++){
        			int j = i+length-1;
        			if(s[i] == s[j] && p[i+1][j-1]){
        				p[i][j] = true;
        				max_beg = i;
        				max_len = length;
        			}
        		}
        	}
        	return s.substr(max_beg,max_len);
        }
    };
    

     

      

     

    Java版
    public class Solution {
        public String longestPalindrome(String s) {
            int n = s.length();
            if( n == 0 ) return s;
            String str = s.substring(0,1);
            boolean[][] dp = new boolean[n][n];
            for ( int i=0;i<n-1;i++ ){
                dp[i][i] = true;
                if( s.charAt(i) == s.charAt(i+1) ){
                    str = s.substring(i,i+2);
                    dp[i][i+1] = true;
                }
            }
            dp[n-1][n-1] = true;
            //初始化完成 O(n)
            for( int i=n-2;i>=0;i-- )
                for( int j=i+2;j<n;j++ ){
                    dp[i][j] = dp[i+1][j-1] && (s.charAt(i) == s.charAt(j));
                    if( dp[i][j] == true && j-i+1 > str.length() )
                        str = s.substring(i,j+1);
                }
            return str;
        }
    }
    

      

    Python版
    s='gsdabcdcbaee'
    l = len(s)
    p = [[False]*l for i in range(l)]
    # init
    max_len , max_beg = 1 , 0
    p[l-1][l-1] = True
    for i in range(l-1):
    	p[i][i] = True
    	if s[i] == s[i+1]:
    		p[i][i+1] = True
    		max_len = 2
    		max_beg = i
    for length in range(3,l+1):
    	for i in range(0,l-length+1):
    		j = i+length-1
    		if s[i] == s[j] and p[i+1][j-1]:
    			p[i][j] = True
    			max_beg = i
    			max_len = length
    print s[max_beg:max_beg+max_len]
    

      

    ——————————————————————————————————
    版本3:中心扩展法    O(n^2) |  O(1)       该方法用Python可A,因为最坏情况才n^2,时间更接近n
    Python
    def Palindromic( s , i , j ):
    	l = len(s)
    	curLen = 0
    	while i>=0 and j<l and s[i] == s[j]:
    		i -= 1
    		j += 1
    	curLen = (j - 1) - (i + 1) + 1
    	return curLen 
    class Solution(object):
        def longestPalindrome(self, s):
            start = 0
            max_len = 1
            for i in range(len(s)):
            
            	curOdd = Palindromic(s,i,i)
            	if curOdd > max_len:
            		max_len = curOdd
            		start = i - curOdd/2
            	if i+1<len(s):
            		curEven = Palindromic(s,i,i+1)
            		if curEven > max_len:
            			max_len = curEven
            			start = i + 1 - curEven/2
            return s[start:start+max_len]
    

      

     
    ——————————————————————————————————
    版本4:Manacher线性算法  O(n)       改进版本3,
    俗称:马拉车算法
    Tip1:插入'#'可以一次性解决奇偶回文问题             abcdcba  ------------->   #a#b#c#d#c#b#a#
    Tip2:记录状态,避免重复计算(回文发生大量重叠 时“abacabaaa”)
    Tip3:避免越界前后设置别的符号作为界限。
     
    状态:P[i]记录以i对应元素为中心的最长回文串的半径(包含自己)。
    状态转移:p[i] = mx>i? min( p[ 2*id-i ] , mx - i ) : 1
     
    该方程分为三种情况
    1、 mx>i 且 mx-i > p[ j ]   (j=2*id-i) ; --> p[ i ] = p [ j ] = p[ 2*id - i ]
    2、mx>i 且 mx-i<=p[ j ] ; ---> p[ i ] >= mx-i 继续匹配。
    3、mx<=i 无法利用p数组,继续匹配。
     
    public class Solution {
        public String longestPalindrome(String s) {
            //预处理
    		StringBuffer sb = new StringBuffer("^#");
    		for( int i=0;i<s.length();i++ ){
    			sb.append(s.substring(i,i+1)+"#");
    		}
    		sb.append("$");
    		String str = sb.toString();
    		//预处理完毕
    		int[] p = new int[str.length()];
    		int mx = 0 , id = 0;
    		for( int i=1;i<str.length()-1;i++ ){
    			p[i] = mx>i ? Math.min( p[ 2*id-i ] , mx - i + 1 ) : 1;
    			while( str.charAt( i+p[i] ) == str.charAt( i-p[i] )) ++p[i];
    			if( p[i] > p[id] ) {
    				id = i;
    				mx = i + p[i] - 1;
    			}
    		}
    		return s.substring( (2 * id - mx - 1) / 2  , (mx-1)/2 );
        }
    }
    

      

     
    ——————————————————————————————————
    版本5:后缀树    O(nlog(n))
     
    暂空
    ——————————————————————————————————
    什么时候使用动态规划法:
    • Optimal substructure    最优子结构
    • Overlapping subproblems 重叠子问题
    构建解的方法:
    Characterize structure of optimal solution   状态
    Recursively define value of optimal solution 状态转移
    Compute in a bottom-up manner 自顶向上
    ——————————————————
  • 相关阅读:
    C#计算一段程序运行时间的三种方法
    jquery easyui combobox设置默认选中第一项
    ASP.NET Web API教程 分页查询
    ASP.NET Web Api 实现数据的分页
    开源.net 混淆器ConfuserEx介绍
    C#软件license管理(简单软件注册机制)
    MyBatis入门实例-包括实体类与数据库字段对应&CLOB字段处理
    MyBatis在insert插入操作时返回主键ID的配置
    MyBatis框架——mybatis插入数据返回主键(mysql、oracle)
    关于java中split的使用
  • 原文地址:https://www.cnblogs.com/flyfatty/p/6656423.html
Copyright © 2011-2022 走看看