• Medium | LeetCode 5. 最长回文子串 | 动态规划 | 中心拓展法


    5. 最长回文子串

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

    示例 1:

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

    示例 2:

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

    示例 3:

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

    示例 4:

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

    提示:

    • 1 <= s.length <= 1000
    • s 仅由数字和英文字母(大写和/或小写)组成

    解题思路

    方法一: 动态规划

    P(i,j) 表示字符串 s 的第 i 到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串, 动态规划方程如下:

    [P(i, j)=P(i+1, j-1) wedgeleft(S_{i}==S_{j} ight) ]

    在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。从边界为0出发, 逐渐向外拓展, 先计算长度为1的子串是否是回文串, 然后计算长度为2的所有子串是否是回文串, 再次基础上再计算长度为3的是否是回文串, 然后逐步计算到长度为N的是否是回文串。

    这种动态规划的算法实际上就是填写一张二维表格, 所以时间复杂度是O(N^2), 空间复杂度是O(N^2).

    public String longestPalindrome(String s) {
        int n = s.length();
        // dp[i][j] 表示 从i到j是一个回文串
        boolean[][] dp = new boolean[n][n];
        String ans = "";
        for (int len = 0; len < n; ++len) {
            for (int i = 0; i + len < n; ++i) {
                int j = i + len;
                if (len == 0) {
                    // 初始化对角线
                    dp[i][j] = true;
                } else if (len == 1) {
                    // 只有两个元素的情况
                    dp[i][j] = (s.charAt(i) == s.charAt(j));
                } else {
                    // 三个及以上元素的情况
                    dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]);
                }
                // 每次找到一个更大的长度的回文子串, 变更新回文子串。
                if (dp[i][j] && len + 1 > ans.length()) {
                    ans = s.substring(i, i + len + 1);
                }
            }
        }
        return ans;
    }
    

    方法二: 中心拓展法

    中心拓展法的思想是, 枚举所有中心。 从中心位置处开始向左右两边延伸, 并且在延伸过程当中分为奇数和偶数两种情况讨论。在延伸直到不可拓展的最大值, 即可得到最大的回文子串。

    这种算法只需要枚举中心并且原地向两端延伸, 所以这种算法的时间复杂度是O(N^2), 不需要其他的任何的额外的存储空间, 所以空间复杂度是O(1)

    public String longestPalindrome(String s) {
        if (s == null || s.length() < 1) {
            return "";
        }
        int start = 0, end = 0;
        for (int i = 0; i < s.length(); i++) {
            // 计算为奇数的回文子串的长度
            int len1 = expandAroundCenter(s, i, i);
            // 计算长度为偶数的回文子串的长度, 并且此字符和下一个字符是回文子串的中心
            int len2 = expandAroundCenter(s, i, i + 1);
            // 得到最大的回文子串的长度
            int len = Math.max(len1, len2);
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }
    
    // 中心拓展法计算回文子串的长度
    public int expandAroundCenter(String s, int left, int right) {
        while (left >= 0 && right < s.length()  // 回文子串的两个指针不能越界。
               && s.charAt(left) == s.charAt(right)) { // 回文子串的两个字符的下标相同
            --left;
            ++right;
        }
        return right - left - 1;
    }
    
  • 相关阅读:
    windows8开发学习笔记
    文字超出隐藏并显示省略号
    list-style-type -- 定义列表样式
    抄录:系统集成项目管理42个子过程
    系统集成项目管理工程师--总结(4章)
    系统集成管理项目工程师总结--口诀2(包含1)
    系统集成管理项目工程师总结--法律法规日期篇1
    关于EAI(一个同学问了我很可爱的问题所以查到的这些)要看看
    系统集成项目管理工程师计划
    中级
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14351084.html
Copyright © 2020-2023  润新知