Leetcode热题100(5) - 最长回文子串

Question

leetcode.cn/problems/lo...

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

示例 1:

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

示例 2:

ini 复制代码
输入:s = "cbbd"
输出:
"bb"

提示:

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

Solution

暴力法

此解法提交Leetcode会超时

暴力法主要有两个步骤:穷举所有子串和判断子串是否问回文串。

  1. 子串的长度从1...N ,所有需要一重循环
  2. 针对每个长度的子串,我们需要遍历子串起点
java 复制代码
lass Solution1 {
        public String longestPalindrome(String s) {
            if (s.length() <= 1) {
                return s;
            }
            int maxLength = 0;
            String maxString = "";
            // 子串长度
            for (int length = 2; length <= s.length(); length++) {
                // 子串起点
                for (int start = 0; start <= s.length() - length; start++) {
                    var end = start + length;
                    var substring = s.substring(start, end);
                    // 如果是回文串且长度大于当前最大的子串长度则更新
                    if (isPalindrome(substring) && substring.length() > maxLength) {
                        maxLength = substring.length();
                        maxString = substring;
                    }
                }
            }
            return maxString;
        }
        
        boolean isPalindrome(String s) {
            var length = s.length();
            for (int i = 0; i < length / 2; i++) {
                if (s.charAt(i) != s.charAt(length - 1 - i)) {
                    return false;
                }
            }
            return true;
        }
    }

时间复杂度

O(n^3), n是字符串长度,我们有两重循环穷举子串,有一重循环检测是否为回文串。

空间复杂度

O(1),需要使用几个固定数量的变量。

动态规划(Dynamic Programing)

对于此类题目,动态规划一般可以用来降维。

根据回文字符串的定义,可以知道字符串的子串是对称的,根据该条件我们可以优化isPalindrome 函数的调用。

假设我们使用二维数组dp[start][end]来存储子串s[start,end]是否为回文串,那么需要讨论以下几种情况:

当s[start] = s[end] 时,考虑如下情况:

  1. 如果start = end, 则s[start] 和 s[end] 是同一个字符,满足回文串条件;
  2. 如果 |start-end|=1 ,则s[start] 和s[end] 相邻,满足回文串条件;
  3. 如果|start-end|=2 ,则s[start] 和s[end] 中间隔了一个字符,满足回文串条件;
  4. 如果|start-end|>2 ,则需要根据上一个子串s[start-1][end+1] 是否为回文串来确定。

因此状态转移方程如下:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> D P ( s t a r t , e n d ) = { s [ s t a r t ] = s [ e n d ] , if ( e n d − s t a r t ) ⩽ 2 D P ( s t a r t − 1 , e n d + 1 ) ∧ s [ s t a r t ] = s [ e n d ] , if ( e n d − s t a r t ) > 2 DP(start,end)=\begin{cases} s[start]=s[end], &\text{if } (end-start) \leqslant 2 \\ DP(start-1, end+1) \land s[start]=s[end], &\text{if } (end-start) \gt 2 \end{cases} </math>DP(start,end)={s[start]=s[end],DP(start−1,end+1)∧s[start]=s[end],if (end−start)⩽2if (end−start)>2

java 复制代码
class Solution2 {

        public String longestPalindrome(String s) {
            if (s.length() <= 1) {
                return s;
            }
            var maxLength = 1;
            var maxBegin = 0;
            var dp = new boolean[s.length()][s.length()];
            // 初始化DP
            for (int i = 0; i < s.length(); i++) {
                dp[i][i] = true;
            }
            // 遍历子串长度
            for (int length = 2; length <= s.length(); length++) {
                // 遍历起点
                for (int start = 0; start <= s.length() - length; start++) {
                    // 计算结束下标
                    var end = start + length - 1;
                    if (s.charAt(start) != s.charAt(end)) {
                        dp[start][end] = false;
                    } else {
                        // 可以直接得出结论
                        if (end - start <= 2) {
                            dp[start][end] = true;
                        } else { // 需要状态转移
                            dp[start][end] = dp[start + 1][end - 1];
                        }
                    }
                    // 当前子串是回文串而且长度比当前最大长度大,则更新最大长度
                    if (dp[start][end] && (end - start + 1) > maxLength) {
                        maxLength = end - start + 1;
                        maxBegin = start;
                    }
                }
            }
            return s.substring(maxBegin, maxBegin + maxLength);
        }
    }

时间复杂度

O(n^2)​, n​是字符串长度。

空间复杂度

O(n^2), n是字符串长度,需要二维数组存储动态规划状态。

中心扩展法

本题还可以使用中心扩展法解答。

对于字符串s 的每个字符s[i] 我们考察s[i-1]s[i+1] 是否相等,如果相等,则继续考察前1个和后一个是否匹配,这就是中心扩展法的核心思想。需要注意的是,回文中心有单个字符和两个相同的相邻字符,如aaa 都是有效的回文中心,因此在编码时需要考虑这两种情况并取长度更长的作为当前位置i 的最优解。

java 复制代码
class Solution3 {

        public String longestPalindrome(String s) {
            if (s.length() <= 1) {
                return s;
            }
            int start = 0;
            int end = 0;
            for (int i = 0; i < s.length(); i++) {
                int len1 = extendCenter(s, i, i); // 中点是同一个字符
                int len2 = extendCenter(s, i, i + 1); // 中点是两个字符
                int len = Math.max(len1, len2);
                if (len > end - start) {
                    start = i - (len - 1) / 2; // 闭区间,所以len-1
                    end = i + len / 2; // 开区间
                }
            }
            return s.substring(start, end + 1);
        }

        private int extendCenter(String s, int start, int end) {
            while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) {
                start--;
                end++;
            }
            // 此时的start和end满足回文条件,因此需要回退一位才是回文串
            // 起点(start+1), 终点(end-1)
            // 距离公式 (end-1)-(start+1)+1
            // 化简得 end-start-1
            return end - start - 1;
        }
    }

需要注意的是在方法extendCenter 中,while 循环结束后startend 构成的子串一定不是回文串(如果是的话循环还会继续),因此在计算当前start~end 的最大回文串长度时需要将startend 进行回退(回退过程见代码注释)。

时间复杂度

O(n^2),n字符串长度,外侧需要遍历字符串,内侧有两个while循环调用,总的时间复杂度为O(n*2n)=O(2n^2) ,化简得O(n^2) .

空间复杂度

O(1), 需要使用常数项的变量。

相关推荐
杜杜的man6 分钟前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
小沈熬夜秃头中୧⍤⃝23 分钟前
【贪心算法】No.1---贪心算法(1)
算法·贪心算法
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
skaiuijing1 小时前
Sparrow系列拓展篇:对调度层进行抽象并引入IPC机制信号量
c语言·算法·操作系统·调度算法·操作系统内核
Star Patrick1 小时前
算法训练(leetcode)二刷第十九天 | *39. 组合总和、*40. 组合总和 II、*131. 分割回文串
python·算法·leetcode
武子康3 小时前
大数据-214 数据挖掘 机器学习理论 - KMeans Python 实现 算法验证 sklearn n_clusters labels
大数据·人工智能·python·深度学习·算法·机器学习·数据挖掘
pianmian18 小时前
python数据结构基础(7)
数据结构·算法
好奇龙猫10 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
sp_fyf_202410 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘