Leetcode中等:5. 最长回文子串

题目:最长回文子串

  • 题号:5
  • 难度:中等
  • https://leetcode-cn.com/problems/longest-palindromic-substring/

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2

输入:s = "cbbd"
输出:"bb"

示例 3

输入: s = "a"
输出: "a"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

实现

回文是一个正读和反读都相同的字符串,例如,“aba”是回文,而“abc”不是。

第一种:暴力法,列举所有的子串,判断该子串是否为回文

  • 执行结果:超出时间限制
public class Solution
{
    public string LongestPalindrome(string s)
    {
        if (string.IsNullOrEmpty(s))
            return string.Empty;
        if (s.Length == 1)
            return s;

        int start = 0;
        int end = 0;
        int len = int.MinValue;
        for (int i = 0; i < s.Length; i++)
        {
            for (int j = i + 1; j < s.Length; j++)
            {
                string str = s.Substring(i, j - i + 1);
                if (isPalindrome(str) && str.Length > len)
                {
                    len = str.Length;
                    start = i;
                    end = j;
                }
            }
        }
        return s.Substring(start, end - start + 1);
    }

    public bool isPalindrome(string s)
    {
        for (int i = 0, len = s.Length / 2; i < len; i++)
        {
            if (s[i] != s[s.Length - 1 - i])
                return false;
        }
        return true;
    }
}

第二种:动态规划

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间

我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。

具体的动态规划算法多种多样,但它们具有相同的填表格式

使用记号 s[l, r] 表示原始字符串的一个子串,lr 分别是区间的左右边界的索引值,使用左闭、右闭区间表示左右边界可以取到。

dp[l, r] 表示子串 s[l, r](包括区间左右端点)是否构成回文串,是一个二维布尔型数组。

  • 当子串只包含 1 个字符,它一定是回文子串;
  • 当子串包含 2 个以上字符的时候:s[l, r] 是一个回文串,那么这个回文串两边各往里面收缩一个字符(如果可以的话)的子串 s[l + 1, r - 1] 也一定是回文串。

故,当 s[l] == s[r] 成立的时候,dp[l, r]的值由 dp[l + 1, r - l] 决定,这里还需要再多考虑一点点:“原字符串去掉左右边界”的子串的边界情况。

  • 当原字符串的元素个数为 3 的时候,如果左右边界相等,那么去掉它们以后,只剩下 1 个字符,它一定是回文串,故原字符串也一定是回文串;
  • 当原字符串的元素个数为 2 的时候,如果左右边界相等,那么去掉它们以后,只剩下 0 个字符,显然原字符串也一定是回文串。

综上,如果一个字符串的左右边界相等,判断为回文只需以下二者之一成立即可:

  • 去掉左右边界以后的字符串不构成区间,即s[l + 1, r - 1]包含元素少于2个,即:r - l <= 2
  • 去掉左右边界以后的字符串是回文串,即dp[l + 1, r - 1] == true

C# 实现

public class Solution {
    public string LongestPalindrome(string s) 
    {
        if (string.IsNullOrEmpty(s))
            return string.Empty;
        int len = s.Length;
        if (len == 1)
            return s;
        int longestPalindromelen = 1;
        string longestPalindromeStr = s.Substring(0, 1);
        bool[,] dp = new bool[len, len];

        for (int r = 1; r < len; r++)
        {
            for (int l = 0; l < r; l++)
            {
                if (s[r] == s[l] && (r - l <= 2 || dp[l + 1, r - 1] == true))
                {
                    dp[l, r] = true;
                    if (longestPalindromelen < r - l + 1)
                    {
                        longestPalindromelen = r - l + 1;
                        longestPalindromeStr = s.Substring(l, r - l + 1);
                    }
                }
            }
        }
        return longestPalindromeStr;        
    }
}

Python 实现

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        count = len(s)
        if count == 0 or count == 1:
            return s
        longestPalindromelen = 1
        longestPalindromeStr = s[0:1]
        dp = [[False] * count for i in range(count)]
        for r in range(1, count):
            for l in range(0, r):
                if s[r] == s[l] and (r - l <= 2 or dp[l + 1][r - 1] == True):
                    dp[l][r] = True
                    if longestPalindromelen < r - l + 1:
                        longestPalindromelen = r - l + 1
                        longestPalindromeStr = s[l:l + longestPalindromelen]
        return longestPalindromeStr

参考文献

  • https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: 最长回文子串可以通过两种方法来实现。第一种是使用中心扩展法,代码如下: ```python class Solution: def check(self, s, l, r): while l >= 0 and r < len(s) and s[l == s[r]: l -= 1 r += 1 return l + 1, r - 1 def longestPalindrome(self, s: str) -> str: start, end = 0, 0 for x in range(len(s)): l1, r1 = self.check(s, x, x) l2, r2 = self.check(s, x, x + 1) if r1 - l1 > end - start: start, end = l1, r1 if r2 - l2 > end - start: start, end = l2, r2 return s[start:end+1] ``` 第二种方法是使用动态规划,代码如下: ```python class Solution: def longestPalindrome(self, s: str) -> str: res = '' for i in range(len(s)): start = max(0, i - len(res) - 1) temp = s[start:i+1] if temp == temp[::-1]: res = temp else: temp = temp<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [5. 最长回文子串(Python 实现)](https://blog.csdn.net/d_l_w_d_l_w/article/details/118861851)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [LeetCode(Python3)5.最长回文子串](https://blog.csdn.net/weixin_52593484/article/details/124718655)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [力扣 (LeetCode)刷题笔记5.最长回文子串 python](https://blog.csdn.net/qq_44672855/article/details/115339324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青少年编程小助手_Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值