题目

给你一个字符串 s,找到 s 中最长的回文子串。

示例 :

输入:s = “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母(大写和/或小写)组成

标签

字符串;动态规划

解题思路

方法:动态规划

对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串“ababa”,如果我们已经知道“bab” 是回文串,那么“ababa” 一定是回文串,这是因为它的首尾两个字母都是 “a”。

根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j) 表示字符串 s的第 i 到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串:
image.png
image.png
image.png

链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/

代码

  1. public class Leetcode5 {
  2. public static void main(String[] args) {
  3. String s = "babad";
  4. System.out.println(longestPalindrome(s));
  5. }
  6. //方法一:动态规划
  7. public static String longestPalindrome(String s) {
  8. int n = s.length();
  9. boolean[][] dp = new boolean[n][n];
  10. String ans = "";
  11. //遍历字符串s, k代表i到j的距离
  12. for (int k = 0; k < n; ++k) {
  13. for (int i = 0; i + k < n; ++i) {
  14. int j = i + k;
  15. if (k == 0) {
  16. //单个字符
  17. dp[i][j] = true;
  18. } else if (k == 1) {
  19. //两个字符
  20. dp[i][j] = (s.charAt(i) == s.charAt(j));
  21. } else {
  22. //大于两个字符
  23. dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]);
  24. }
  25. //只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
  26. if (dp[i][j] && k + 1 > ans.length()) {
  27. ans = s.substring(i, i + k + 1);
  28. }
  29. }
  30. }
  31. return ans;
  32. }
  33. //方法二:动态规划2
  34. public static String longestPalindrome2(String s) {
  35. int len = s.length();
  36. // 特判
  37. if (len < 2) {
  38. return s;
  39. }
  40. int maxLen = 1;
  41. int begin = 0;
  42. // 1. 状态定义
  43. // dp[i][j] 表示s[i...j] 是否是回文串
  44. // 2. 初始化
  45. boolean[][] dp = new boolean[len][len];
  46. for (int i = 0; i < len; i++) {
  47. dp[i][i] = true;
  48. }
  49. char[] chars = s.toCharArray();
  50. // 3. 状态转移
  51. // 注意:先填左下角
  52. // 填表规则:先一列一列的填写,再一行一行的填,保证左下方的单元格先进行计算
  53. for (int j = 1; j < len; j++) {
  54. for (int i = 0; i < j; i++) {
  55. // 头尾字符不相等,不是回文串
  56. if (chars[i] != chars[j]) {
  57. dp[i][j] = false;
  58. } else {
  59. // 相等的情况下
  60. // 考虑头尾去掉以后没有字符剩余,或者剩下一个字符的时候,肯定是回文串
  61. if (j - i < 3) {
  62. dp[i][j] = true;
  63. } else {
  64. // 状态转移
  65. dp[i][j] = dp[i + 1][j - 1];
  66. }
  67. }
  68. // 只要dp[i][j] == true 成立,表示s[i...j] 是回文串
  69. // 此时更新记录回文长度和起始位置
  70. if (dp[i][j] && j - i + 1 > maxLen) {
  71. maxLen = j - i + 1;
  72. begin = i;
  73. }
  74. }
  75. }
  76. // 4. 返回值
  77. return s.substring(begin, begin + maxLen);
  78. }
  79. }

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/