1. 程式人生 > >leetcode-5-最長迴文子串(longest palindromic substring)-java

leetcode-5-最長迴文子串(longest palindromic substring)-java

題目及測試

package pid005;
/*最長迴文子串

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。

示例 1:

輸入: "babad"
輸出: "bab"
注意: "aba"也是一個有效答案。

示例 2:

輸入: "cbbd"
輸出: "bb"






*/
public class main {
	
	public static void main(String[] args) {
		String[] testTable = {"babad","cbbd","ccc","eabcb"};
		for (int i=0;i<testTable.length;i++) {
			test(testTable[i]);
		}
	}
		 
	private static void test(String ito) {
		Solution solution = new Solution();
		String rtn;
		long begin = System.currentTimeMillis();
		System.out.println("ito="+ito);
		rtn = solution.longestPalindrome(ito);//執行程式
		long end = System.currentTimeMillis();		
		System.out.println("rtn="+rtn);
		System.out.println();
		System.out.println("耗時:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,138ms,很慢)
對0到length-1進行迴圈(不能迴圈到中間,因為字串後半段也有可能有會文字串)
對每個index,進行奇數會文和偶數會文的判斷,奇數是兩邊相等,偶數是自身與右邊相等
記錄max的length和substring

package pid005;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

public class Solution {
public String longestPalindrome(String s) {
    int length=s.length();
    if(length<=1){
    	return s;
    }
    int maxLength=0;
    String maxString="";
    for(int i=0;i<length;i++){//4 2(1)  5 3(2)
    	//首先檢查以自己為中心(奇數會文)
    	int j=1;
    	int nowlength=1;
    	while(i-j>=0&&i+j<length){
    		if(s.charAt(i-j)==s.charAt(i+j)){
    			j++;
    			nowlength=nowlength+2;
    		}
    		else{
    			break;
    		}
    	}    	
    	if(nowlength>maxLength){
    		maxString=s.substring(i-(int)Math.floor(nowlength/2), i+(int)Math.floor(nowlength/2)+1);
    		maxLength=nowlength;
    	}
    	//檢查偶數會文
    	j=0;
    	nowlength=0;
    	while(i-j>=0&&i+j+1<length){
    		if(s.charAt(i-j)==s.charAt(i+j+1)){
    			j++;
    			nowlength=nowlength+2;
    		}
    		else{
    			break;
    		}
    	}
    	if(nowlength>maxLength){
    		maxLength=nowlength;
    		maxString=s.substring(i-nowlength/2+1, i+nowlength/2+1);
    	}
    	
    }
    
	return maxString;
    }

}

解法2(別人的)

動態規劃:

(一般含“最XX”等優化詞義的題意味著都可以動態規劃求解),時間複雜度O(n^2),空間複雜度O(n^2)。
 形如"abba", "abbba"這樣的字串,如果用dp[i][j]表示從下標i到j之間的子字串所構成的迴文子串的長度,則有:
 dp[i][j] = dp[i+1][j-1] && s[i] == s[j]
初始化:
 奇數個字元:dp[i][i] = 1; 偶數個字元:dp[i][i+1] = 1
若長度相同,返回最後一個子串
 

public String longestPalindrome(String s) {
		if (s == null || s.length() <= 1)
			return s;
		int n = s.length();
		char[] cs = s.toCharArray();
		int max = 1;
		int maxIndex = 0;
		boolean dp[][] = new boolean[n][n];
		// 初始化一個字母
		for (int i = 0; i < n; i++) {
			dp[i][i] = true;
			maxIndex = i;
		}
		// 初始化兩個相同的字母"aa"
		for (int i = 0; i < n - 1; i++)
			if (cs[i] == cs[i + 1]) {
				dp[i][i + 1] = true;
				// 返回最後一為2的子串
				max = 2;
				maxIndex = i;
			}
		// 從長度3開始操作, (aba)ba, a(bab)a, ab(aba)
		for (int len = 3; len <= n; len++)
			for (int i = 0; i < n - len + 1; i++) {
				// j為從i~i + len - 1下標,長度為len
				int j = i + len - 1;
				// 字元相同,並且內部長度是迴文
				if (cs[i] == cs[j] && dp[i + 1][j - 1]) {
					max = len;
					// 因為長度遞增,如果之後的的能進入這裡都是比之前長的,
					// 所以不需要判斷大小
					maxIndex = i;
					dp[i][j] = true;
				}
			}
		return s.substring(maxIndex, maxIndex + max);
	}

解法3(別人的)

使用manacher演算法

https://www.cnblogs.com/z360/p/6375514.html

http://blog.sina.com.cn/s/blog_70811e1a01014esn.html