原题:
Alan觉得回文串是个好东西,可是Alan忘记怎么做了,于是想请你帮帮忙:
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案的个数。
输入格式:
输入一个字符串s
0 ≤ len(s) ≤ 64
输出格式:
输出一个整数代表方案个数。
输入样例:
aab
输出样例:
2
样例解释
所有可能的方案是:
[
["aa","b"],
["a","a","b"]
]
输入样例:
aabccb
输出样例:
6
样例解释:
所有可能的方案是:
[
['a', 'a', 'b', 'c', 'c', 'b'],
['a', 'a', 'b', 'cc', 'b'],
['a', 'a', 'bccb'],
['aa', 'b', 'c', 'c', 'b'],
['aa', 'b', 'cc', 'b'],
['aa', 'bccb']
]
思路:
用递归的思路,要判断n个字符是否是回文串,也就是依次判断第一个和剩余n-1个字符是否是回文串,然后剩余n-1个字符又可以变成第2个和剩余n-2个字符串是否是…这样递归下去。同时,用一个for循环,来确定每次分割的长度。
代码:
#include<bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
bool judge(string str)
{
string copy_str = str;
reverse(str.begin(),str.end());
return str == copy_str;
}
long long dfs(string str)
{
if (str.size() <= 1) return 1;
long long ans = 0;
for (int i = 0; i < str.size(); ++i)
{
if (judge(str.substr(0, i + 1)))
{
ans = ans + dfs(str.substr(i+1)) % MOD;
ans = ans % MOD;
}
}
return ans;
}
int main()
{
string s;
getline(cin, s);
if (s.empty()) cout << 0 << endl;
else
cout << dfs(s);
return 0;
}
扩展:
输入一个字符串s 0 ≤ len(s) ≤ 200。
数量可能会很大,请将答案mod1000000007。
此时用之前的方法,会因为递归的次数过多,而超时。
改进:
在判断的时候,有的回文串是重复的,这样的话就会造成重复的递归,进行不必要的判断。因此,可以通过一个map容器来进行存放:该字符串分割成回文串的分割个数。每次进行分割的时候,若map容器查询到该回文串的值,则直接返回结果。以此实现记忆化搜索。
改进版代码:
#include<bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
map<string, long long>mp;
bool judge(string str)
{
string copy_str = str;
reverse(str.begin(), str.end());
return str == copy_str;
}
long long dfs(string str)
{
if (str.size() <= 1) return 1;
long long ans = 0;
for (int i = 0; i < str.size(); ++i)
{
//是回文串
if (judge(str.substr(0, i + 1)))
{
string restStr = str.substr(i + 1);
//判断之前是否保存过结果。若未计算过,则返回0
if (mp.count(restStr) == 0)
{
mp[restStr] = dfs(restStr) % MOD;
}
ans = (ans + mp[restStr]) % MOD;
}
}
return ans;
}
int main()
{
string s;
getline(cin, s);
if (s.empty()) cout << 0 << endl;
else
cout << dfs(s);
return 0;
}