回文系列算法题总结

Posted by GH on December 16, 2020

在我刚开始工作的时候,很多公司都喜欢考回文的算法,知道现在依旧很多大小厂都喜欢考这类题目,这里总结一下解法

1. 动态规划解题 –> 时间复杂度:(O(N^2))

动态规划的问题重点就是:理清楚状态转移方程 计算最长回文子串算法题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public String longestPalindrome(String s) {
    if (s == null || s.equals("")) {
        return "";
    }


    int n = s.length();
    boolean[][] isPalindrome = new boolean[n][n];

    // 初始化
    // 1个的
    int start = 0;
    int longest = 1;
    for (int i = 0; i < n; i++) {
        isPalindrome[i][i] = true;
    }

    // 2个的
    for (int i = 0; i < n - 1; i++) {
        isPalindrome[i][i+1] = s.charAt(i) == s.charAt(i+1);
        if (isPalindrome[i][i+1]) {
            start = i;
            longest = 2;
        }
    }

    // x  abba   y
    // ^         ^
    // i         j
    // 状态转移方程 isPalindrome[i][j] = isPalindrome[i+1][j-1] && s.charAt(i) == s.charAt(j)
    for (int i = n - 1; i >= 0; i--) {
        for (int j = i + 2; j < n; j++) {
            isPalindrome[i][j] = isPalindrome[i+1][j-1] && s.charAt(i) == s.charAt(j);
            if (isPalindrome[i][j] && j - i + 1 > longest) {
                start = i;
                longest = j - i + 1;
            }
        }
    }

    return s.substring(start, start + longest);
}
  • 计算最长回文子序列的长度算法题: 子串和子序列还是有本质上差别的这里要理清楚
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* @param s: the maximum length of s is 1000
* @return: the longest palindromic subsequence's length
*/
public int longestPalindromeSubseq(String s) {
// write your code here
if (s == null || s.equals("")) {
    return 0;
}

// 字符长度
int n = s.length();
// 定义一个二维数组:longestPalindrome[i][j] 表示 坐标i与坐标j之间的最长子序列的值
int[][] longestPalindrome = new int[n][n];
// 初始化
// 1. 赋值1个字符的情况
int longest = 1;
for (int i = 0; i < n; i++) {
    longestPalindrome[i][i] = 1;
}

// 2. 赋值2个字符的情况
for (int i = 0; i < n - 1; i++) {
    longestPalindrome[i][i+1] = s.charAt(i) == s.charAt(i+1) ? 2 : 1;
    if (longestPalindrome[i][i+1] == 2) {
        longest = 2;
    }
}

// 3. 其他情况
// 状态转移方程
// longestPalindrome[i][j] = s.charAt(i) == s.charAt(j) ?
//                           longestPalindrome[i + 1][j - 1] + 2
//                           max(longestPalindrome[i][j - 1], longestPalindrome[i + 1][j])
for (int i = n; i >= 0; i--) {
    for (int j = i + 2; j < n; j ++) {
        longestPalindrome[i][j] = s.charAt(i) == s.charAt(j) ? longestPalindrome[i + 1][j - 1] + 2 : Math.max(longestPalindrome[i][j - 1], longestPalindrome[i + 1][j]);
        if (longestPalindrome[i][j] > longest) {
            longest = longestPalindrome[i][j];
        }
    }
}

return longest;
}

2. 中心线枚举法 –> 时间复杂度:(O(N^2))

计算最长回文子串算法题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public String longestPalindrome(String s) {
    if (s == null || s.equals("")) {
        return "";
    }

    String longestString = "";
    for (int i = 0; i < s.length(); i++) {
        // odd
        String odd_longestPalindrome = getSubString(s, i, i);
        if (odd_longestPalindrome.length() > longestString.length()) {
            longestString = odd_longestPalindrome;
        }

        // even
        String even_longestPalindrome = getSubString(s, i, i + 1);
        if (even_longestPalindrome.length() > longestString.length()) {
            longestString = even_longestPalindrome;
        }
    }
    return longestString;
}

private String getSubString(String s, int left, int right) {
    while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
        left--;
        right++;
    }
    return s.substring(left + 1, right);
}

3. 暴力解法【我这里就不写了,你可以自己尝试一下】