返回

用Swift 轻松解决力扣第5题:最长回文子串

闲谈

掌握 LeetCode 5:使用动态规划查找最长回文子串

简介

回文子串是一个从左到右和从右到左读都相同的字符串。在处理字符串问题时,找到字符串中的最长回文子串是一个常见的挑战。LeetCode 5 题正是提出了这样的挑战,要求我们编写一个算法来确定给定字符串中的最长回文子串。

算法概述

为了解决这个问题,我们将使用动态规划技术。动态规划是一种将问题分解成较小子问题的强大算法范例,然后逐步解决这些子问题,直到找到最终解决方案。

算法步骤

我们的动态规划算法将遵循以下步骤:

1. 定义回文子串的长度

我们将使用一个二维数组 dp 来记录字符串的每个位置的子串是否为回文子串。dp[i][j] 表示从位置 ij 的子串是否是回文子串,其中 i < j

2. 初始化数组

首先,我们将数组 dp 的对角线上的元素设为 True,因为长度为 1 的子串显然是回文子串。

3. 动态规划

我们将使用双重循环,从长度为 2 的子串开始,依次考虑更长的子串。对于每一个长度为 l 的子串,我们使用子问题 dp[i][j] 来表示从位置 i 到位置 j 的子串是否为回文子串。我们有以下三种情况:

  • s[i] = s[j]l > 2,则 dp[i][j] = dp[i + 1][j - 1]
  • s[i] = s[j]l <= 2,则 dp[i][j] = True
  • 其他情况,dp[i][j] = False

代码示例(Swift)

以下是使用 Swift 实现该算法的代码示例:

func longestPalindrome(s: String) -> String {
    // 特殊情况处理
    if s.isEmpty {
        return ""
    }

    // 构造二维数组dp
    let n = s.count
    var dp = Array(repeating: Array(repeating: false, count: n), count: n)

    // 初始化dp数组的对角线为True
    for i in 0..<n {
        dp[i][i] = true
    }

    // 动态规划算法求解dp数组
    var maxLength = 1
    var start = 0
    for l in 2...n {
        for i in 0...(n - l) {
            let j = i + l - 1
            if s[i] == s[j] {
                if l == 2 || dp[i + 1][j - 1] {
                    dp[i][j] = true
                    if l > maxLength {
                        maxLength = l
                        start = i
                    }
                }
            }
        }
    }

    // 查询dp数组中的最长回文子串的长度
    return String(s[start...(start + maxLength - 1)])
}

示例

考虑字符串 s = "babad"。使用我们的算法,我们可以找到最长回文子串为 "bab"

常见问题解答

1. 如果给定的字符串中没有回文子串,该怎么办?

在这种情况下,算法将返回一个空字符串 ""

2. 如何处理重叠的回文子串?

我们的算法将找到最长的回文子串,即使它包含其他较短的回文子串。

3. 这个算法的时间复杂度是多少?

该算法的时间复杂度为 O(n^2),其中 n 是给定字符串的长度。

4. 这个算法的空间复杂度是多少?

该算法的空间复杂度也为 O(n^2),因为我们使用二维数组 dp 来存储子问题的解决方案。

5. 有没有比动态规划更好的解决方法?

有,有一种称为 Manacher 算法的更有效的算法,它可以在线性时间内找到最长回文子串。

结论

使用动态规划,我们可以有效地解决 LeetCode 5 题,即在给定字符串中找到最长回文子串。通过分解问题并逐步解决子问题,我们可以轻松找到问题的最佳解决方案。