zoukankan      html  css  js  c++  java
  • 【LeetCode】回文串专题

    目录

    【LeetCode】5.最长回文子串

    【LeetCode】680. 验证回文字符串 Ⅱ


    【LeetCode】5.最长回文子串

    题目链接

    https://leetcode-cn.com/problems/longest-palindromic-substring/

    题目描述

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

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

    解题思路

    (1)暴力求解

    字符串问题,首先就是想到暴力的方法。

    找出字符串s的所有子串,并对所有子串进行判断其是否为回文串,如果字符串s有多个不同长度的回文子串,则用ans以及maxx迭代更新最长回文子串以及最长回文子串的长度。时间复杂度为O(n3),基本上是超时的。

    (2)中心扩展法

    思路:

    • 长度为奇数的回文子串中心有一个元素,例如 "aba" 的中心元素为 "b" ;

    • 长度为偶数的回文子串中心有两个元素,例如 "abba" 的中心元素为 "bb" 。

    • 分别以两种中心为基础寻找并比较出最长回文子串。

    (3)动态规划(本题的解法与LCS类型)

    动态规划一般也只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。
    
    动态规划算法分以下4个步骤:
    
    (1)描述最优解的结构
    (2)递归定义最优解的值
    (3)按自底向上的方式计算最优解的值   //此3步构成动态规划解的基础。4)由计算出的结果构造一个最优解。   //此步如果只要求计算最优解的值时,可省略。
    好,接下来,咱们讨论适合采用动态规划方法的最优化问题的俩个要素:最优子结构性质,和子问题重叠性质。
    
    (1)最优子结构
        如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。意思就是,总问题包含很多个子问题,而这些子问题的解也是最优的。
    
    (2)重叠子问题
        子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

    该问题满足最优子结构性质:一个最长回文串去掉两头以后,剩下的部分依然是最长回文串。

    第一步:定义状态

    dp[i][j]:表示子串s[i,j]是否为回文子串。

    当dp[i][j] = 1:表示子串s[i,j]为回文子串,反之。

    第二步:状态转移方程

    这一步在做分类讨论(根据头尾字符是否相等)。

     if j-i >= 2

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

    dp[i][j] = 0, if dp[i+1][j-1] == 0 || s[i] != s[j]

    else

    dp[i][j] = 1,if s[i] == s[j]

    dp[i][j] = 0,if s[i] != s[j]

    Q:j-i >= 2这个条件是如何求解出来的?

    A:因为dp[i][j]表示子串s[i,j]是否为回文子串,所以i<=j,同理dp[i+1][j-1]中,i+1 <= j-1,整理得j - i <= 2.

    第三步:考虑初始化

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

    第四步:考虑输出

    只要一得到dp[i][j] = 1,就记录子串的长度和起始位置,没必要利用substr函数截取,因为截取字符串也要消耗性能,记录此时的回文子串的“起始位置”和“回文长度”即可。

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

    (4)观察法

    观察子串,回文字数要么是偶数个,那么类似cbaabc这种中间是aa的;要么是奇数个,类似是cbabc中间是bab型的,仅此两种。所以用for先找偶数型(aa)回文,找s[i]=s[i+1],找到后再往两边推,直到s[i-len]与s[i+1+len]不等为止,记录此子串的位置和长度,最后进行长度比较。再找s[i]=s[i+2],即找奇数型(aba)回文,找到后处理同上。

    AC代码

    (2) 中心扩展法

     1 class Solution {
     2     public String longestPalindrome(String s) {
     3         if (s.isEmpty()) {
     4             return "";
     5         }
     6         // 记录最长回文子串开始和结束的位置。
     7         int start = 0, end = 0;
     8         for (int i = 0; i < s.length(); i++) {
     9             // 查找以当前元素为中心的最长回文子串长度。
    10             int len1 = function(s, i, i);
    11             // 查找以当前元素和下一个元素为中心的最长回文子串长度。
    12             int len2 = function(s, i, i + 1);
    13             int maxLen = Math.max(len1, len2);
    14             // 判断记录遍历过位置能找到的最长回文子串起始位置。
    15             if (maxLen > end - start) {
    16                 start = i - (maxLen - 1) / 2;
    17                 end = i + maxLen / 2;
    18             }
    19         }
    20         return s.substring(start, end + 1);
    21     }
    22 
    23     private int function(String s, int left, int right) {
    24         // 以传入的相邻两位置为中心找最大回文子串长度,两位置相同表示一个元素为中心。
    25         while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
    26             left--;
    27             right++;
    28         }
    29         return right - left - 1;
    30     }
    31 }

    (3)动态规划法

     1 class Solution {
     2 public:
     3     string longestPalindrome(string s) {
     4         if(s.size() == 0 || s.size() == 1 || (s.size() == 2 && s[0] == s[1])) return s;
     5         vector<vector<int> > dp(s.size(),vector<int>(s.size())); //二维vector数组的初始化方式
     6         int index = 0;
     7         int len = 0;
     8         for(int i = 0; i < s.size(); i++) dp[i][i]=1;
     9         for(int j = 1; j < s.size(); j++)
    10         {
    11             for(int i = 0; i < j; i++)
    12             {
    13                 if(j - i < 2)
    14                 {
    15                     if(s[i] == s[j]) dp[i][j] = 1; //dp[i][j]=1表示字符串s[i]-s[j]为回文串,反之。
    16                     else dp[i][j] = 0;
    17                 }
    18                 else
    19                 {
    20                     if(dp[i+1][j-1] == 1 && s[i] == s[j]) dp[i][j] = 1;
    21                     else dp[i][j] = 0;
    22                 }
    23                 
    24                 if(dp[i][j] == 1 && j-i+1>len) //迭代更新,利用len记录回文串的最大长度
    25                 {
    26                     index = i;
    27                     len = j-i+1;
    28                 }
    29             }
    30         }
    31         if(len == 0) return s.substr(0,1);
    32         else return s.substr(index,len);
    33     }
    34 };

    (4)观察法

     1 class Solution {
     2 public:
     3 string longestPalindrome(string s) 
     4 {
     5     const int slen = s.length();
     6     int i,t;
     7     int max = 0;
     8     t = 0;
     9     for (i = 0; i < slen; i++) //该for循环判断cbaabc类型的回文串
    10     {
    11         if(s[i]==s[i+1])
    12             {
    13                 int hlen=1;
    14                 while((i-hlen>=0) && (i+1+hlen<=slen-1)&&(s[i-hlen]==s[i+1+hlen]))
    15                     hlen++;
    16                 if (2 * hlen > max)
    17                 {
    18                     max = 2 * hlen;
    19                     t = i-hlen+1;
    20                 }
    21             }
    22     }
    23     for (i = 0; i < slen-1; i++)//该for循环判断cbabc类型的回文串
    24     {
    25         if (s[i] == s[i + 2])
    26         {
    27             int hlen = 1;
    28             while ((i - hlen >= 0 //防止数组下标越界) && (i + 2 + hlen <= slen-1//防止数组下标越界) && (s[i - hlen] == s[i + 2 + hlen]))
    29                 hlen++;
    30             if (2 * hlen + 1 > max)
    31             {
    32                 max = 2 * hlen + 1;
    33                 t = i-hlen+1;
    34             }
    35         }
    36     }
    37     if (max==0)
    38         return s.substr(0,1);
    39     else
    40         return s.substr(t, max);
    41 }
    42 };

    【LeetCode】680. 验证回文字符串 Ⅱ

    题目链接

    https://leetcode-cn.com/problems/valid-palindrome-ii/

    题目描述

    给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

    示例 1:
    输入: "aba"
    输出: True
    示例
    2: 输入: "abca" 输出: True 解释: 你可以删除c字符。
    注意: 字符串只包含从 a
    -z 的小写字母。字符串的最大长度是50000。

    解题思路

    1.暴力枚举

    先判断字符串S是否为回文字符串,如果是则返回true,如果不是按顺序删除字符串S中的每一个字符,然后判断剩余的字符串是否为回文字符串即可。

    2.双指针

    当检查到前后不一样的字符,必须要删掉一个(要么开头,要么结尾)。删掉之后检查剩下的字符串是否为回文。是则返回TRUE,反之。

    AC代码

    双指针

     1 class Solution {
     2 public:
     3     bool ispalindrome(string s) //判读字符串S是否为回文字符串,这样的时间复杂度为O(n/2)
     4     {
     5         int start = 0;
     6         int end = s.size()-1;
     7         while(start <= end)
     8         {
     9             if(s[start] != s[end]) return false;
    10             start++;
    11             end--;
    12         }
    13         return true;
    14     }
    15     bool validPalindrome(string s) {
    16         int start = 0;
    17         int end = s.size()-1;
    18         if(s.size()<=2) return true;
    19         while(start <= end)
    20         {
    21             if(s[start] == s[end])
    22             {
    23                 start++;
    24                 end--;
    25             }
    26             else
    27             {
    28                 int len = end-start;
    29                 string temp = s.substr(start+1,len);//当两个元素不相同时,删除前面一个元素,判断剩下的元素是否为回文串
    30                 if(ispalindrome(temp)) return true;
    31                 string te = s.substr(start,len);//当两个元素不相同时,删除后面一个元素,判断剩下的元素是否为回文串
    32                 if(ispalindrome(te)) return true;
    33                 return false;
    34             }
    35         }
    36         return true;
    37     }
    38 };
  • 相关阅读:
    第七课——iOS数据持久化
    第三章-动态规划
    IOS第五课——Gesture and TableView
    第六课——UIDynamicAnimator
    文本居中换行、边框设置
    属性优先级、图片属性设置、内联标签设置大小
    打开、悬浮、访问、点击、状态用:
    属性选择器用【】
    组合使用用逗号,
    3种选择器的使用方式
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/12889836.html
Copyright © 2011-2022 走看看