回文字符串
像"aavbvaa"这样正着反着读都一样的字符串就是回文字符串
单个字符串
判断方法一
从字符串的两端进行比对,相同i++,j–,直到到达i>=j
bool check(string s){
int i,j=s.size()-1;
for(i=0;i<str.length()/2;i++,j--)
if(str[i]!=str[j]) break; //如果有一个不相匹配就结束循环
if(i>=j) return 1;
return 0;
}
判断方法二
无需采用指针,因为计算机除法向下取整的缘故,奇数长度的字符串的中位数无需判断
bool check(string s){
int len=s.size()-1;
for(int i=0;i<=len/2;i++){
if(s[i]!=s[len-i]) return 0;
}
return 1;
}
字符串区间
给出一个字符串。判断其任意长度的子串是否为回文串,下面默认字符串区间为[1,len]
暴力
实际上以字符串的某个字符为中心,使用双指针向两边扩散,但是要分为三种情况具体讨论
- 回文串长度为奇数,那么该字符为中位数,初始指针分别为该元素下标的前一个和后一个
- 回文串长度为偶数,且该字符作为中心线偏左的元素,初始指针分别为该元素下标本身和后一个
- 回文串长度为偶数,且该字符作为中心线偏右的元素,初始指针分别为该元素下标本身和前一个
bool vis[maxn][maxn];
char s[maxn];
for(int i=1;i<=n;i++){
vis[i][i]=1;
int l=i-1,r=i+1;
while(l>=1 && r<=n && s[l]==s[r]){
vis[l][r]=1;
l--,r++;
}
l=i,r=i+1;
while(l>=1 && r<=n && s[l]==s[r]){
vis[l][r]=1;
l--,r++;
}
l=i-1,r=i;
while(l>=1 && r<=n && s[l]==s[r]){
vis[l][r]=1;
l--,r++;
}
}
dp
设dp(i,j),i<=j代表区间[i,j]的子串为回文串
考虑双重循环,第一层枚举字符串所有字符,第二层枚举它前面的所有字符,那么显然这里存在一个递推关系
-
当s[i]==s[j]且i-j>1且dp(j+1,i-1)==1时,显然dp(j,i)=1
-
当s[i]==s[j]且i-j<=1时,dp(j,i)=1
bool dp[maxn][maxn];
char s[maxn];
for(int i=1;i<=n;i++){
dp[i][i]=1;
for(int j=1;j<i;j++)
if(s[i]==s[j]){
if(i-j<=1) dp[j][i]=1;
else if(dp[j+1][i-1])
dp[j][i]=1;
}
}