回文串
回溯
分割回文串
思路
回溯模板:每次传入起始位置,for循环遍历不同子串,若子串回文则递归;直到起始位置==s.size()
代码
class Solution {
public:
vector<vector<string>> result;
vector<string> path;
void backTracking(string s,int index){
if(index == s.size()){
result.emplace_back(path);
return;
}
for(int i=0;i<s.size()-index;i++){
string subs = s.substr(index,i+1);
if(!IsHuiwen(subs))continue;
path.emplace_back(subs);
backTracking(s,index+i+1);
path.pop_back();
}
}
bool IsHuiwen(string s){
int left=0,right=s.size()-1;
while(left<=right){
if(s[left]!=s[right])return false;
left++;
right--;
}
return true;
}
vector<vector<string>> partition(string s) {
backTracking(s,0);
return result;
}
};
动态规划
回文子串
思路
DP数组直接令为dp[i]表示以下标i结尾的字符串有 dp[i]个回文串的话,很难找到和dp[i-1],dp[i+1]的关系
根据回文串的性质:若要判定s[i..j]是否回文,可判定s[i+1..j-1]是否回文 & s[i] == s[j]
因此dp数组令为二维数组dp[i][j]表示s[i..j]是否回文。
递推公式:
s[i]==s[j]时:
- 子串长度为1 或 2 ,dp[i][j] = true
- 否则dp[i][j] = dp[i+1][j-1]
遍历顺序
由于要用到dp[i+1][j-1],因此必须从下至上,从左至右遍历
代码
class Solution {
public:
int countSubstrings(string s) {
int n = s.size();
vector<vector<bool>> dp(n,vector<bool>(n,false));
//dp[i][j]表示s[i]-s[j]的子串是回文子串
int result=0;//每判断有一个回文字串就+1
for(int i=n-1;i>-1;i--){// 从下到上
for(int j=i;j<n;j++){// 从左往右
if(s[i] == s[j]){
if(j - i <= 1 || dp[i+1][j-1]){//i==j 和i+1 == j
result++;
dp[i][j] = true;
// }else if(dp[i+1][j-1]){//i+1<j时,看区间[i+1,j-1]是否是回文
// result++;
// dp[i][j] = true;// 如果是则[i,j]也是回文
}
}
}
}
return result;
}
};
最长回文子串
整体代码和回文子串一样
代码
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
vector<vector<bool>> dp(len,vector<bool>(len,false));//dp[i][j]表示s[i...j]是否是回文串
int maxlen=0;
int begin=0;
// 递推公式 要看dp[i+1][j-1] 所以遍历要从下到上,从左往右
for(int i=len-1;i>-1;i--){
for(int j=i;j<len;j++){// i<=j 所以让j从i开始,其他的s[i...j]是非法字符串
if(s[i] == s[j]){
if(j-i < 2 || dp[i+1][j-1]){
dp[i][j] = true;
if (j - i + 1 > maxlen){
begin = i;
maxlen = j-i+1;
}
}
}
}
}
return s.substr(begin,maxlen);
}
};
双指针法 / 中心拓展法(优化空间复杂度O(1))
“回文子串”也适用
思路
选取一个中心,根据中心向两边拓展,如果两边相等就是回文串。
一个元素可以作为中心点,两个元素也可以作为中心点。但三个四个可由一个两个拓展来所以不必。
代码
- for循环遍历中心点
- extend向两边拓展
- 记录最长字符串的起始点和长度最后substr
class Solution {
public:
int maxlen=0;
int left=0;
void extend(const string& s,int i,int j,int n){//i和j是中心
while(i >=0 && j < n && s[i] == s[j]){// 当前是回文串
if(j - i + 1 > maxlen){
maxlen = j-i+1;
left = i;
}
i--;
j++;
}
}
string longestPalindrome(string s) {
int n = s.size();
if(n == 1)return s;
for(int i=0;i<n;i++){
extend(s,i,i,s.size());
extend(s,i,i+1,s.size());
}
return s.substr(left,maxlen);
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架