题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

  1. 输入: "babad"
  2. 输出: "bab"
  3. 注意: "aba" 也是一个有效答案。

示例 2:

  1. 输入: "cbbd"
  2. 输出: "bb"

题解

暴力法

暴力法将选出所有子字符串可能的开始和结束位置,并检验它是不是回文。

  1. public class Solution
  2. {
  3. public string LongestPalindrome(string s)
  4. {
  5. if (s.Length == 0) return "";
  6. var longest = s.Substring(0, 1);
  7. for (var i = 0; i < s.Length ; i++)
  8. {
  9. var s1 = ExpandAroundCenter(s, i, i);
  10. if (s1.Length > longest.Length) longest = s1;
  11. var s2 = ExpandAroundCenter(s, i, i + 1);
  12. if (s2.Length > longest.Length) longest = s2;
  13. }
  14. return longest;
  15. }
  16. private string ExpandAroundCenter(string s, int left, int right)
  17. {
  18. var l = left;
  19. var r = right;
  20. while (l >= 0 && r < s.Length && s[l] == s[r])
  21. {
  22. l--;
  23. r++;
  24. }
  25. return s.Substring(l + 1, r - (l + 1));
  26. }
  27. }

动态规划

参考:Grandyang

我们维护一个二维数组 dp,其中 dp[i,j] 表示字符串区间 [i, j] 是否为回文串。

  • 当 i = j 时,只有一个字符,肯定是回文串

  • 如果 i = j + 1,说明是相邻字符,此时需要判断 s[i] 是否等于 s[j]

  • 如果 i 和 j 不相邻,即i - j >= 2时,除了判断 s[i] 和 s[j] 相等之外,dp[j + 1,i - 1] 若为真,就是回文串

通过以上分析,可以写出递推式如下:
dp[i,j] = true if i == j
= s[i] == s[j] if j = i + 1
= s[i] == s[j] && dp[i+1,j-1] if j > i + 1

  1. public static string LongestPalindrome(string s)
  2. {
  3. if (string.IsNullOrEmpty(s)) return "";
  4. // dp[i,j] 表示字符串区间 [i,j] 是否为回文串
  5. var dp = new bool[s.Length, s.Length];
  6. int left = 0, right = 0, len = 0;
  7. for (var i = 0; i < s.Length; i++)
  8. {
  9. for (var j = 0; j < i; ++j)
  10. {
  11. dp[j, i] = s[i] == s[j] && (i - j < 2 || dp[j + 1, i - 1]);
  12. if (dp[j, i] && len < i - j + 1)
  13. {
  14. len = i - j + 1;
  15. left = j;
  16. right = i;
  17. }
  18. }
  19. dp[i, i] = 1!=0;
  20. }
  21. return s.Substring(left, right - left + 1);
  22. }