返回
炼技术于实践:每日一道算法题挑战之——LeetCode 5 最长回文子串
人工智能
2023-09-17 02:09:48
题目剖析:
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题“最长回文子串”是一道经典的算法题,考察了算法设计和动态规划的应用。通过剖析题目、分析解法、实现代码和性能分析,我们对回文子串的性质和算法的奥妙有了更深入的理解。希望这篇文章能为你带来启发,助你成为一名更强大的算法高手!