LeetCode 647. Palindromic Substrings的三种解法
转载地址
https://www.cnblogs.com/AlvinZH/p/8527668.html#_label5
题目详情
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 1:
输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".
示例 2:
输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".
注意:
- 输入的字符串长度不会超过1000。
题目分析
一个小问题,子串(Substring)、子数组(Subarray)和子序列(Subsequence)的区别:子串和子数组是等同的,特点是连续的,比如[1,2,3]的子串有(1), (2), (3), (1,2), (2,3), (1,2,3)。而子序列不一定相邻,但相对顺序一致,比如(1,3)是[1,2,3]的一个子序列。
方法有很多种,简单讲一些。
方法一: DP
一开始定义DP[i][j]为i、j之间的回文子串数,很是麻烦,还需要另外的数组记录子串[i, j]是否是回文的。其实没有必要,直接将DP[i][j]定义成子串[i, j]是否是回文串。外循环 i从 n−1 往 0 遍历,内循环 j 从 i 往 n−1 遍历,若s[i]==s[j]:
若i==j,则dp[i][j]=true;
若i和j是相邻的,则dp[i][j]=true;
若i和j中间只有一个字符,则dp[i][j]=true;
否则,检查dp[i+1][j-1]是否为true,若为true,那么dp[i][j]就是true。
前三条可以合并,即 j−i≤2。求得dp[i][j]真值后,如果其为true,最终结果res++。
时间复杂度:O(n^2)。
方法一参考代码:
class Solution {
public:
int countSubstrings(string s) {
int len = s.size(), res = 0;
vector<vector<bool>> dp(len, vector<bool>(len, false));
for (int i = len - 1; i >= 0; --i) {
for (int j = i; j < len; ++j) {
dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
if (dp[i][j]) ++res;
}
}
return res;
}
};
方法二:回文中心法
本题可以不用DP,而是采用一种巧妙的方法:回文中心法。什么意思呢?考虑不同的回文中心,往两边扩散,求得回文数。需要考虑两种情况:如果是奇数长度回文串,了么回文中心为最中间的一个字符;如果是偶数长度回文串,这回文中心为最中间的两个字符。
每个回文子串只有一个回文中心,所以这种方法不会重复计算,也不会漏算。
时间复杂度:O(n^2)。
方法二参考代码:
class Solution {
public:
int countSubstrings(string s) {
int len = s.size(), res = 0;
for (int i = 0; i < len; ++i) {
int mid1 = i, mid2 = i;//奇数
while (mid1 >= 0 && mid2 < len && s[mid1] == s[mid2]) {
--mid1; ++mid2; ++res;
}
mid1 = i, mid2 = i+1;//偶数
while (mid1 >= 0 && mid2 < len && s[mid1] == s[mid2]) {
--mid1; ++mid2; ++res;
}
}
return res;
}
};
方法三:“马拉车”算法
神奇的算法,先马一下,学会再写上。听说时间复杂度是 O(n)。
好了,学到了,请参考:什么是马拉车算法?
利用马拉车算法,可以得到所有情况下的最大半径,以s[i]为中心,RL[i]为半径的回文串中含有的字回文串数目是 RL[i]/2 个。
方法三参考代码:
class Solution {
public:
int countSubstrings(string s) {
//预处理
string t = "#";
for (int i = 0; i < s.size(); ++i) {
t += s[i];
t += "#";
}
vector<int> RL(t.size(), 0);
int MaxRight = 0, pos = 0;
int res = 0;
for (int i = 0; i < t.size(); ++i) {
RL[i] = MaxRight > i ? min(RL[2 * pos - i], MaxRight - i) : 1;
while (i-RL[i] >=0 && i+RL[i] < t.size() && t[i + RL[i]] == t[i - RL[i]])//扩展,注意边界
++RL[i];
//更新最右端及其中心
if (MaxRight < i + RL[i] -1) {
MaxRight = i + RL[i] -1;
pos = i;
}
res += RL[i]/2;
}
return res;
}
};
LeetCode 647. Palindromic Substrings的三种解法的更多相关文章
- [LeetCode] 647. Palindromic Substrings 回文子字符串
Given a string, your task is to count how many palindromic substrings in this string. The substrings ...
- Leetcode 647. Palindromic Substrings
Given a string, your task is to count how many palindromic substrings in this string. The substrings ...
- LeetCode算法题-Move Zeroes(Java实现-三种解法)
这是悦乐书的第201次更新,第211篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第67题(顺位题号是283).给定一个数组nums,写一个函数将所有0移动到它的末尾,同 ...
- LeetCode算法题-First Bad Version(Java实现-三种解法)
这是悦乐书的第200次更新,第210篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第66题(顺位题号是278).您是产品经理,目前领导团队开发新产品.不幸的是,您产品的最 ...
- 【LeetCode】647. Palindromic Substrings 解题报告(Python)
[LeetCode]647. Palindromic Substrings 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/p ...
- 【LeetCode】647. Palindromic Substrings 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:暴力循环 方法二:固定起点向后找 方法三:动 ...
- [LeetCode] Remove Element (三种解法)
Given an array and a value, remove all instances of that value in place and return the new length. T ...
- 【Leetcode】647. Palindromic Substrings
Description Given a string, your task is to count how many palindromic substrings in this string. Th ...
- 647. Palindromic Substrings 互文的子字符串
[抄题]: Given a string, your task is to count how many palindromic substrings in this string. The subs ...
随机推荐
- GPO - Disabling Task Manager Access
Create a GPO to disable Task Manager Access to normal users. Add an exception to Domain Admins.
- 集训作业 洛谷P1143 进制转换
这个题目就是让我们实现进制的转换. 我只会很简单的把他从一个别的进制转化成10进制,然后再继续转化成目标进制. #include<iostream> #include<cstdio& ...
- C++语法小记---面向对象模型(实例的内存分布)
面向对象的模型(内存分布) 对于一个对象而言,成员变量和成员函数是分开存放的 成员函数位于代码段,所有的类对象共有 成员变量为每一个对象独有,位于内存中 类对象在内存中的分布和struct完全相同 对 ...
- 最简单的VScode Python 开发环境配置以及中文化
前置条件 Python 3.X(2020年了,建议使用Python3.X版本) 一.下载VSCode VSCode官方下载链接 由于安装过程是中文界面,此处略过. 二.VSCode中文化 不需要配置什 ...
- 一个调用其他activity的完整例子,使用了 onActivityResult和startActivityForResult
https://blog.csdn.net/qq_32521313/article/details/52451364 Android startActivityForResult基本用法2016年09 ...
- Object#wait()与Object#wait(long)的区别
例子 例1 最基础的等待-通知 下面一个例子,一个线程"waiting"在同步代码块调用了Object#wait()方法,另一个线程"timedWaiting" ...
- Django学习路19_is_delete属性,重写类方法,显性隐性属性
如果在 创建数据表时,使用了 objects = models.Model() 使隐形属性变为了 显性属性 则 必须要自己定义一个 继承了 models.Model 类的类,实现 管理功能 如果一个属 ...
- yield 复习
1.协程,微型进程: yield 生成器 yield 会保存声明的变量,可以进行迭代 使用 接收函数返回的对象.__next__() next(接收函数返回的对象) .send() 方法 传递给函数中 ...
- PHP user_error() 函数
定义和用法 user_error() 函数创建用户自定义的错误消息. user_error() 函数用于在用户指定的条件下触发一个错误消息.它可以与内建的错误处理程序一起使用,或者与由 set_err ...
- ARC 062 F - Painting Graphs with AtCoDeer 割点 割边 不动点 burnside引理
LINK:Painting Graphs with AtCoDeer 看英文题面果然有点吃不消 一些细节会被忽略掉. 问每条边都要被染色 且一个环上边的颜色可以旋转. 用c种颜色有多少本质不同的方法. ...