返回

炼技术于实践:每日一道算法题挑战之——LeetCode 5 最长回文子串

人工智能

题目剖析:

LeetCode第5题要求你找出给定字符串中最长的回文子串。回文子串是指从左到右读和从右到左读都一样的子字符串。例如,在字符串“abba”中,“abba”和“bb”都是回文子串。

直观解法:

乍一看,我们可以采用双重循环的方法来解决这个问题。外层循环枚举字符串中的每一个字符作为回文子串的中心,内层循环则负责检查以该字符为中心的最长回文子串。这种方法虽然简单粗暴,但时间复杂度高达O(n^2),对于长字符串来说,效率低下。

巧用动态规划:

为了提高效率,我们可以引入动态规划的思想。我们定义一个二维数组dp,其中dp[i][j]表示字符串s[i]到s[j]能否构成回文串。这个数组可以很方便地通过下面的递推关系来计算:

dp[i][j] = true if s[i] == s[j] and (i + 1 > j or dp[i + 1][j - 1])

从这个递推关系可以看出,当字符串s[i]和s[j]相等且i+1和j-1之间的字符串也是回文串时,s[i]到s[j]的子串也是回文串。

代码实现:

def longest_palindrome(s):
  """
  Finds the longest palindromic substring in a given string.

  Args:
    s: The string to search.

  Returns:
    The longest palindromic substring.
  """

  # Initialize the dp array.
  dp = [[False for _ in range(len(s))] for _ in range(len(s))]

  # Populate the dp array.
  for i in range(len(s) - 1, -1, -1):
    for j in range(i, len(s)):
      if s[i] == s[j] and (i + 1 > j or dp[i + 1][j - 1]):
        dp[i][j] = True

  # Find the longest palindromic substring.
  start = 0
  end = 0
  for i in range(len(s)):
    for j in range(i, len(s)):
      if dp[i][j] and j - i + 1 > end - start + 1:
        start = i
        end = j

  return s[start:end + 1]


# Example usage.
s = "abba"
print(longest_palindrome(s))  # Output: "abba"

s = "abcba"
print(longest_palindrome(s))  # Output: "abcba"

s = "forgeeksskeegfor"
print(longest_palindrome(s))  # Output: "geeksskeeg"

性能分析:

使用动态规划的方法,我们可以将时间复杂度降低到O(n^2),空间复杂度也降低到O(n^2)。这种方法对于长字符串来说,效率有了显著的提升。

进一步优化:

如果我们只关心最长回文子串的长度,而不是子串本身,那么我们可以进一步优化代码。我们可以使用一个一维数组来记录最长回文子串的长度,并在计算dp数组的过程中不断更新这个长度。这样,我们可以将时间复杂度降低到O(n),空间复杂度也降低到O(n)。

总结:

LeetCode第5题“最长回文子串”是一道经典的算法题,考察了算法设计和动态规划的应用。通过剖析题目、分析解法、实现代码和性能分析,我们对回文子串的性质和算法的奥妙有了更深入的理解。希望这篇文章能为你带来启发,助你成为一名更强大的算法高手!