LeetCode - Medium - 5. Longest Palindromic Substring

今天药忘吃喽~ 2022-12-31 12:28 225阅读 0赞

Topic

  • String
  • Dynamic Programming

Description

https://leetcode.com/problems/longest-palindromic-substring/

Given a string s, return the longest palindromic substring in s.

Example 1:

  1. Input: s = "babad"
  2. Output: "bab"
  3. Note: "aba" is also a valid answer.

Example 2:

  1. Input: s = "cbbd"
  2. Output: "bb"

Example 3:

  1. Input: s = "a"
  2. Output: "a"

Example 4:

  1. Input: s = "ac"
  2. Output: "a"

Constraints:

  • 1 <= s.length <= 1000
  • s consist of only digits and English letters (lower-case and/or upper-case),

Analysis

方法一:以字符为中心向其两侧扩展探测是否回文。


方法二:动态规划。

dp(i, j) represents whether s(i ... j) can form a palindromic substring, dp(i, j) is true when s(i) equals to s(j) and s(i+1 ... j-1) is a palindromic substring.

When we found a palindrome, check if it’s the longest one. Time complexity O(n^2).

以 s = “babad” 为例,dp数组如下:

  1. j 0 1 2 3 4
  2. i b a b a d
  3. 0 b t t
  4. 1 a t t
  5. 2 b t
  6. 3 a t
  7. 4 d t
  • j must be greater than or equal i at all times. Why? i is the start index of the substring, j is the end index of the substring. It makes no sense for i to be greater than j. If you visualize the dp 2d array, think of a diagonal that cuts from top left to bottom right. We are only filling the top right half of dp.
  • Why are we counting down for i, but counting up for j? Each sub-problem dp[i][j] depends on dp[i+1][j-1] (dp[i+1][j-1] must be true and s.charAt(i) must equal s.charAt(j) for dp[i][j] to be true).
  • How to understand dp[i][j] = s.charAt(i) == s.charAt(j) && (j - i < 3 || dp[i + 1][j - 1]);?

    • j-i == 0, only a character is a palindrome.
    • j-i == 1 and s.charAt(i) == s.charAt(j), s[i:j] is a palindrome.(like “aa”,“bb”)
    • j-i == 2 and s.charAt(i) == s.charAt(j), no matter what between i and j, s[i:j] is a palindrome.(like “aba”, “aza”)

动态规划解决问题的套路

  • 需要用动态规划解决问题的味道

    • “最值”味道。(本题的 the longest palindromic substring in s)
  • 用动态规划解决问题的4步曲

    1. 确定状态。(dp(i, j) represents whether s(i ... j) can form a palindromic substring)
    2. 求得方程。(dp[i][j] = s.charAt(i) == s.charAt(j) && (j - i < 3 || dp[i + 1][j - 1]);
    3. 设初置界。(0 <= i <= j < s.length)
    4. 确序而答。(由方程可知,dp[i][j]是依赖dp[i + 1][j - 1]的,因此,i从大到小,j则从小到大)

Submission

  1. public class LongestPalindromicSubstring {
  2. // 方法一:以中心字符扩展探测回文
  3. public String longestPalindrome1(String s) {
  4. int maxLen = 0, startIndex = 0;
  5. for (int i = 0; i < s.length(); i++) {
  6. int len1 = extend(s, i, i);
  7. int len2 = extend(s, i, i + 1);
  8. int tempMax = Math.max(len1, len2);
  9. if (tempMax > maxLen) {
  10. maxLen = tempMax;
  11. startIndex = len1 > len2 ? i - len1 / 2 : i - len2 / 2 + 1;
  12. }
  13. }
  14. return s.substring(startIndex, startIndex + maxLen);
  15. }
  16. private int extend(String s, int i, int j) {
  17. for (; i > -1 && j < s.length(); i--, j++) {
  18. if (s.charAt(i) != s.charAt(j))
  19. break;
  20. }
  21. return j - i - 1;
  22. }
  23. // 方法二:使用动态规划算法
  24. public String longestPalindrome2(String s) {
  25. int sLength = s.length();
  26. String res = null;
  27. boolean[][] dp = new boolean[sLength][sLength];
  28. //startIndex相当于i,endIndex相当于j,改名方便理解。
  29. for (int startIndex = sLength - 1; startIndex >= 0; startIndex--) {
  30. for (int endIndex = startIndex; endIndex < sLength; endIndex++) {
  31. dp[startIndex][endIndex] = s.charAt(startIndex) == s.charAt(endIndex) //
  32. && (endIndex - startIndex < 3 || dp[startIndex + 1][endIndex - 1]);
  33. if (dp[startIndex][endIndex] && (res == null || endIndex - startIndex + 1 > res.length())) {
  34. res = s.substring(startIndex, endIndex + 1);
  35. }
  36. }
  37. }
  38. return res;
  39. }
  40. }

Test

  1. import static org.junit.Assert.*;
  2. import static org.hamcrest.Matchers.*;
  3. import org.junit.Test;
  4. public class LongestPalindromicSubstringTest {
  5. @Test
  6. public void test() {
  7. LongestPalindromicSubstring obj = new LongestPalindromicSubstring();
  8. assertEquals("bb", obj.longestPalindrome1("cbbd"));
  9. assertEquals("a", obj.longestPalindrome1("a"));
  10. assertThat(obj.longestPalindrome1("ac"), anyOf(is("a"), is("c")));
  11. assertThat(obj.longestPalindrome1("babad"), anyOf(is("bab"), is("aba")));
  12. assertEquals("bb", obj.longestPalindrome2("cbbd"));
  13. assertEquals("a", obj.longestPalindrome2("a"));
  14. assertThat(obj.longestPalindrome2("ac"), anyOf(is("a"), is("c")));
  15. assertThat(obj.longestPalindrome2("babad"), anyOf(is("bab"), is("aba")));
  16. }
  17. }

发表评论

表情:
评论列表 (有 0 条评论,225人围观)

还没有评论,来说两句吧...

相关阅读