用Swift 轻松解决力扣第5题:最长回文子串
2023-11-24 21:42:07
掌握 LeetCode 5:使用动态规划查找最长回文子串
简介
回文子串是一个从左到右和从右到左读都相同的字符串。在处理字符串问题时,找到字符串中的最长回文子串是一个常见的挑战。LeetCode 5 题正是提出了这样的挑战,要求我们编写一个算法来确定给定字符串中的最长回文子串。
算法概述
为了解决这个问题,我们将使用动态规划技术。动态规划是一种将问题分解成较小子问题的强大算法范例,然后逐步解决这些子问题,直到找到最终解决方案。
算法步骤
我们的动态规划算法将遵循以下步骤:
1. 定义回文子串的长度
我们将使用一个二维数组 dp
来记录字符串的每个位置的子串是否为回文子串。dp[i][j]
表示从位置 i
到 j
的子串是否是回文子串,其中 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 题,即在给定字符串中找到最长回文子串。通过分解问题并逐步解决子问题,我们可以轻松找到问题的最佳解决方案。