We say a sequence of characters
is a palindrome if it
is the same written forwards
and backwards. For example,
‘racecar’ is a palindrome, but
‘fastcar’ is not.
A partition of a sequence of
characters is a list of one or
more disjoint non-empty groups
of consecutive characters whose
concatenation yields the initial
sequence. For example, (‘race’,
‘car’) is a partition of ‘racecar’
into two groups.
Given a sequence of characters,
we can always create a partition
of these characters such
that each group in the partition
is a palindrome! Given this observation
it is natural to ask:
what is the minimum number of
groups needed for a given string
such that every group is a palindrome?
For example:
• ‘racecar’ is already a
palindrome, therefore it
can be partitioned into
one group.
• ‘fastcar’ does not contain
any non-trivial palindromes,
so it must be partitioned
as (‘f’, ‘a’, ‘s’, ‘t’,
‘c’, ‘a’, ‘r’).
• ‘aaadbccb’ can be partitioned
as (‘aaa’, ‘d’, ‘bccb’).
Input
Input begins with the number n of test cases. Each test case consists of a single line of between 1 and
1000 lowercase letters, with no whitespace within.
Output
For each test case, output a line containing the minimum number of groups required to partition the
input into groups of palindromes.
Sample Input
3
racecar
fastcar
aaadbccb
Sample Output
1
7
3
题意:给定一个字符串,找到字符串中回文子串的最小数量。
思路:枚举i~j并判断是否为回文子串,如果是的话状态转移DP[i]=min(DP[i],DP[j-1]+1)
时间复杂度O(N*N*N)
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<math.h>
#include<string>
using namespace std;
//最小回文串数量
const int maxn=1005;
const int INF=0x3f3f3f3f;
int DP[maxn];//以i结尾的最小回文串数量
char str[maxn];
int main()
{
int N;
scanf("%d",&N);
while(N--)
{
memset(str,'\0',sizeof(str));
memset(DP,0x3f3f,sizeof(DP));
scanf("%s",str+1);
DP[0]=0;
int len=strlen(str+1);
for(int i=1; i<=len; i++)
{
for(int j=1; j<=i; j++)
{
bool is_huiwen=true;//从j到i是不是回文串
for(int k=j,t=i; k<=t; k++,t--)
if(str[k]!=str[t])
{
is_huiwen=false;
break;
}
if(is_huiwen==true)
{
DP[i]=min(DP[j-1]+1,DP[i]);
}
}
}
printf("%d\n",DP[len]);
}
return 0;
}
还可以提前预处理出DP[i][j]代表以i开头长度为j的字符串是否为回文串。
查询时候和上面一样枚举i~j,直接通过预处理结果就可以判断出是否为回文。
时间复杂的O(N*N),不过常数略大。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<math.h>
#include<string>
using namespace std;
//最小回文串数量
const int maxn=1005;
const int INF=0x3f3f3f3f;
bool DP[maxn][maxn];//标记以i开头长度为j的字符串是否为回文串
int result[maxn];//以i结尾的最小回文串数量
char str[maxn];
int main()
{
int N;
scanf("%d",&N);
while(N--)
{
memset(result,0x3f,sizeof(result));
memset(str,'\0',sizeof(str));
memset(DP,false,sizeof(DP));
scanf("%s",str+1);
int len=strlen(str+1);
for(int i=1; i<=len; i++)
DP[i][1]=true;//以i开头长度为1的字符串是回文串
for(int i=1; i<=len-1; i++)
if(str[i]==str[i+1])
DP[i][2]=true;//以i开头长度为2的字符串是回文串
for(int j=3; j<=len; j++)//枚举长度
for(int i=1; i<=len-j+1; i++)//枚举起点
if(DP[i+1][j-2]==true&&str[i]==str[i+j-1])
DP[i][j]=true;//拓展回文串
result[0]=0;
for(int i=1; i<=len; i++)
for(int j=1; j<=i; j++)
if(DP[i-j+1][j]==true)
result[i]=min(result[i],result[i-j]+1);
printf("%d\n",result[len]);
}
return 0;
}