【探索-中级算法】最长回文子串

版权声明:转载请标明出处「OneDeveloper」 https://blog.csdn.net/OneDeveloper/article/details/83540207

在这里插入图片描述

这一题可以参考:647. 回文子串

本质上是一样的,要判断出所有的回文字串,然后找到其中最长的那一个。


中心扩展法

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)

public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    char[] strs = s.toCharArray();
    int len = strs.length;
    int[] arr1 = new int[2];
    int[] arr2 = new int[2];
    //记录起点与终点的位置
    int start = 0, end = 0;
    for (int i = 0; i < len; i++) {
        //以 s(i) 为中心向两边扩散,得到最长的回文子串
        get(arr1, strs, i - 1, i + 1);
        //以 s(i) 与 s(i+1) 为中心向两边扩散,得到最长的回文子串
        get(arr2, strs, i, i + 1);
        int tmpStart, tmpEnd;
        if (arr1[1] - arr1[0] > arr2[1] - arr2[0]) {
            tmpStart = arr1[0];
            tmpEnd = arr1[1];
        } else {
            tmpStart = arr2[0];
            tmpEnd = arr2[1];
        }
        if ((tmpEnd - tmpStart) > (end - start)) {
            start = tmpStart;
            end = tmpEnd;
        }
    }
    return s.substring(start, end + 1);
}
public void get(int[] arr, char[] strs, int left, int right) {
    while (left >= 0 && right < strs.length && strs[left] == strs[right]) {
        --left;
        ++right;
    }
    ++left;
    --right;
    arr[0] = left;
    arr[1] = right;
}

基于动态规划

public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    int len = s.length();
    boolean dp[][] = new boolean[len][len];
    char[] strs = s.toCharArray();
    int start = 0, end = 0;
    // 判断 dp[i][i+1] 是不是回文
    for (int i = 0; i < len -1 ; i++) {
        if(strs[i] == strs[i + 1]) {
            dp[i][i + 1] = true;
            start = i;
            end = i + 1;
        }
		// dp[i][i] 即单个字母肯定是回文
        dp[i][i] = true;
    }	
    //因为上面的循环无法设置最后一个字母,所以要在这里设置
    dp[len - 1][len - 1] = true;

	// 按照 dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j])) 
	// 的转移方程来判断 dp[i][j] 是不是回文
	// 如果是的话还要与原有最长的比较是不是更长且记录
    for (int i = len - 3; i >= 0; i--) {
        for (int j = i+2; j < len; j++) {
            dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j]));
            if (dp[i][j]) {
                if (j - i > end - start) {
                    start = i;
                    end = j;
                }
            }
        }
    }
    return s.substring(start, end + 1);
}

dp[i][j] 表示 s 的子串 s[i,j] 是不是回文。

需要注意的就是第二个循环遍历的顺序如下图所示(折线表示计算的顺序):
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/OneDeveloper/article/details/83540207