回文串的切割(记忆化搜索改进版)

原题:

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;
}

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值