• LeetCode 5. 最长回文子串


    5. 最长回文子串

    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

    示例 1:

    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。
    示例 2:

    输入: "cbbd"
    输出: "bb"

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/longest-palindromic-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    题解

      最常用的方法应该有三个,暴力解,动态规划和中心扩展,

      动态规划

      当字符串长度为1的时候,必然是个回文串,那长度为3的情况下呢,就需要s[i] == s[i + 3]的情况下才能形成回文

      或者说长度为2时,需要s[i] == s[i + 1]形成回文

      so,可以得出个结论,子串从 i 到 j 如果想是个回文,需满足两个条件:

      1. 子串[i + 1, j - 1]是个回文

      2.字符s[i] == s[j]

      SO, 可以得出状态方程

      dp[i, j] = dp[i + 1, j - 1] && s[i] == s[j]

      用个dp[s.len][s.len]来表示子串从i到j是否是回文串,未必最长回文串;  

      在dp总,dp[i][i]比如是个回文,因为长度只有1(i - i + 1);

      所以可以将dp[i][i]直接先赋值为true,并且作为最初始的判断条件

            for (int i = 0; i < len; i++) {
                dp[i][i] = true;
            }

      进而考虑边界条件dp[i + 1][j - 1]的边界问题:

      如果从s[i + 1, j - 1]的长度小于2,既为0 或者1的时候:

      如果是0,那必然是回文; 如果是1,则只需要判断s[i] s[j]是否相等即可,可以把这两个判定归类在s[i]==s[j]的情况下,dp[i][j]为回文

      代码如下:

    string longestPalindrome(string s) {
            // 特判
            int len = s.length();
            if (len < 2) {
                return s;
            }
    
            int maxLen = 1;
            int begin = 0;
    
            // dp[i][j] 表示 s[i, j] 是否是回文串
            vector<vector<int>> dp(len, vector<int>(len));
    
            for (int i = 0; i < len; i++) {
                dp[i][i] = true;
            }
            for (int j = 1; j < len; j++) {
                for (int i = 0; i < j; i++) {
                    printf("str = %s 
    ", s.substr(i, j - i + 1).c_str());
    
                    if (s[i] != s[j]) {
                        dp[i][j] = false;
                    }
                    else {
                        if (j - i < 3) { //(j-1) - (i+1) + 1 < 2 从i到j的内部小于等于1
                            dp[i][j] = true;
                        }
                        else {
                            dp[i][j] = dp[i + 1][j - 1];
                        }
                    }
    
                    // 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
                    if (dp[i][j] && j - i + 1 > maxLen) {
                        maxLen = j - i + 1;
                        begin = i;
                    }
                }
            }
            return s.substr(begin, begin + maxLen);
    }

      中心扩展

       核心思想是对每个字符以及两个字符中间作为中心点,向两边扩展,判定是否是回文,得出最长

      为什么是每个字符以及两个字符中间作为中心点呢,因为字符长度可以是基数或者偶数

    class Solution {
    public:
        pair<int, int> expandAroundCenter(const string& s, int left, int right) {
            while (left >= 0 && right < s.size() && s[left] == s[right]) {
                --left;
                ++right;
            }
            return {left + 1, right - 1};
        }
    
        string longestPalindrome(string s) {
            int start = 0, end = 0;
            for (int i = 0; i < s.size(); ++i) {
                auto [left1, right1] = expandAroundCenter(s, i, i);
                auto [left2, right2] = expandAroundCenter(s, i, i + 1);
                if (right1 - left1 > end - start) {
                    start = left1;
                    end = right1;
                }
                if (right2 - left2 > end - start) {
                    start = left2;
                    end = right2;
                }
            }
            return s.substr(start, end - start + 1);
        }
    };

      另:马拉车算法

      太复杂了,等我看明白先!!!

      

  • 相关阅读:
    #树#遍历#N叉树的前序遍历
    #树#递归#最大二叉树II
    #树#递归#二叉树的镜像
    #树#递归#最大二叉树
    #树#二叉搜索树的最近公共祖先
    #树#二叉树的直径
    #树#N叉树的后序遍历
    #树#判断平衡二叉树
    webpack+react+nodejs+express前端开发环境搭建
    sublime 玩转react+es6
  • 原文地址:https://www.cnblogs.com/gongkiro/p/13637223.html
Copyright © 2020-2023  润新知