zoukankan      html  css  js  c++  java
  • [LeetCode] 5. Longest Palindromic Substring 最长回文子串

         本题求给定字符串的最长回文子串,首先可以想到使用暴力的方法,求出给定字符串的所有的回文子串的长度,取长度最长的子串,具体地分回文子串长度为奇数和长度为偶数讨论,时间复杂度O(n^2),但此暴力求解的方法在leetcode上会报超时错误,具体代码如下:

    一. 暴力法

    参考代码

    #include<string>
    #include<string.h>
    using namespace std;
    class Solution {
    public:
        string longestPalindrome(string s) {
           if(s.empty()||s.size()<=1) return s;
           int size = s.size();
           string odd_str = longestPalindrome_odd(s,size);
           string even_str = longestPalindrome_even(s,size); 
           return odd_str.size() >= even_str.size()?odd_str:even_str;
        }
        
        string longestPalindrome_odd(string& s,int size)
        {
           string res;
           for(int i = 0; i<size; ++i){
               string substr =  s.substr(i,1);
               for(int l = i-1,r = i+1;l>=0 && r<=size-1;l--,r++){
                    if(s[l]!=s[r]) break;
                     else{
                       substr = s.substr(l,r-l+1);
                    }
               }
               if(substr.size()>=res.size()) res = substr;
           }
           return res;
        }
    
        string longestPalindrome_even(string& s,int size)
        {
            string res; 
            for(int i = 0; i<size; ++i){
                string substr;
                for(int l = i,r = i+1;l>=0&&r<=size-1;l--,r++){
                    if(s[l]!=s[r]) break;
                    else{
                      substr = s.substr(l,r-l+1);
                    }
                }
                if(substr.size()>=res.size()) res = substr;
            }
            return res;
        }
    };

    二  动态规划:

    第 1 步:定义状态
        dp[i][j] 表示子串 s[i, j] 是否为回文子串。定义状态先尝试“题目问什么,就把什么设置为状态”。然后考虑“状态如何转移”,如果“状态转移方程”不容易得到,尝试修改状态定义,目的仍然是为了方便得到“状态转移方程”。

    第 2 步:思考状态转移方程

       这一步在做分类讨论(根据头尾字符是否相等),根据对状态定义的分析得到:

    dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
    分析这个状态转移方程:

    (1)“动态规划”事实上是在填一张二维表格,i 和 j 的关系是 i <= j ,因此,只需要填这张表的上半部分;

    (2)在 s[i] == s[j] 成立和 j - i < 3 的前提下,直接可以下结论,dp[i][j] = true,否则才执行状态转移。

      注:分类讨论是构造转态转移方程的技巧。对状态空间进行分类,思考最优子结构到底是什么。即大问题的最优解如何由小问题的最优解得到。

    第 3 步:考虑初始化

    初始化的时候,单个字符一定是回文串,因此把对角线先初始化为 1,即 dp[i][i] = 1 。

    事实上,初始化的部分都可以省去。因为只有一个字符的时候一定是回文,dp[i][i] 根本不会被其它状态值所参考。

    第 4 步:考虑输出
    只要一得到 dp[i][j] = true,就记录子串的长度和起始位置,没有必要截取,因为截取字符串也要消耗性能,记录此时的回文子串的“起始位置”和“回文长度”即可。

    第 5 步:考虑状态是否可以压缩
    因为在填表的过程中,只参考了左下方的数值。事实上可以压缩,但会增加一些判断语句,增加代码编写和理解的难度,丢失可读性。在这里不做状态压缩。

    下面是编码的时候要注意的事项:总是先得到小子串的回文判定,然后大子串才能参考小子串的判断结果。

    思路是:

    1、在子串右边界 j 逐渐扩大的过程中,枚举左边界可能出现的位置;

    2、左边界枚举的时候可以从小到大,也可以从大到小。

    参考代码2 :

    class Solution {
    public:
        string longestPalindrome(string s) {
            const int size = s.size();
            if(s.empty()||size <= 1)
               return s;
            int l=0,h=0,seq=0;
           bool dp[size][size];
            for(int j = 1;j<size;++j)
               for(int i = 0;i<=j;++i)
                {
                    int sub_seq = j-i+1;
                    if(sub_seq<3)
                    {
                        dp[i][j]=s[i]==s[j];
                    }
                    else
                    {
                         dp[i][j]=(s[i]==s[j]&&dp[i+1][j-1]);
                    }
                    if(dp[i][j]&&sub_seq>=seq){
                        l=i;
                        h=j;
                        seq=sub_seq;
                    }
                }
                return s.substr(l,seq);
        }
    };
  • 相关阅读:
    16.5 函数对象
    16.4.7 无序关联容器(C++11)
    16.4.6 关联容器
    16.4.5 容器种类(外1:7种序列容器类型)
    16.4.5 容器种类(下:序列)
    # SpringBoot + Spring AMQP 整合 RabbitMQ
    RabbitMQ 消息模型
    RabbitMQ Docker 单机与集群部署
    RabbitMQ 核心概念入门
    MQ消息中间件 + JMS + AMQP 理论知识
  • 原文地址:https://www.cnblogs.com/wangxf2019/p/12157561.html
Copyright © 2011-2022 走看看