dp:扰乱字符串

Leetcode, ScrambleString

首先想到的是递归(即深搜),对两个 string 进行分割,然后比较四对字符串。代码虽然简单,但是复杂度比较高。有两种加速策略,一种是剪枝,提前返回;一种是加缓存,缓存中间结果,即memorization(翻译为记忆化搜索)。
既然可以用记忆化搜索,这题也一定可以用动规。设状态为 f[n][i][j],表示长度为 n,起点为 s1[i] 和起点为 s2[j] 两个字符串是否互为 scramble,则状态转移方程为:
f[n][i][j]} = (f[k][i][j] && f[n-k][i+k][j+k]) || (f[k][i][j+n-k] && f[n-k][i+k][j])

#include <iostream>
#include <string>
#include <vector>
using namespace std;

typedef string::iterator Iter;
bool isScramble( Iter first1, Iter last1, Iter first2 )
{
	auto len = std::distance(first1, last1 );
	auto last2 = std::next(first2, len);

	if (len == 1)
		return *first1 == *first2;

	for ( int i = 1; i < len; ++i )
	{
		//s1 = gr, s2 = rg 第一个条件返回false,第二个条件返回true
		if ((isScramble(first1, first1 + i, first2)
			&& isScramble(first1 + i, last1, first2 + i))	
			|| (isScramble(first1, first1 + i, last2 - i)
				&& isScramble(first1 + i, last1, first2)))
		return true;
	}	
	return false;
}
//递归,会超时,仅用来帮助理解
//时间复杂度 O(n^6),空间复杂度 O(1)
int solution( string s1, string s2 )
{
	return isScramble(s1.begin(), s1.end(), s2.begin());
}
//动规,时间复杂度 O(n^3),空间复杂度 O(n^3)
int solution1(string s1, string s2)
{
	const int N = s1.size();
	if (N != s2.size()) return false;

	//f[n][i][j],表示长度为 n,起点为 s1[i] 和
	//起点为 s2[j] 两个字符串是否互为 scramble
	vector<vector<vector<bool>>> vec(N + 1, vector<vector<bool>>(N, vector<bool>(N, false)));
	//基线条件,只取一个字符时
	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j )
			vec[1][i][j] = s1[i] == s2[j];

	for (int n = 1; n <= N; ++n)
	{
		for ( int i = 0; i + n <= N; ++i )
		{
			for ( int j = 0; j + n <= N; ++j)
			{
				//枚举每个子串
				for ( int k = 1; k < n; ++k)
				{
					if ((vec[k][i][j] && vec[n - k][i + k][j + k])
						|| (vec[k][i][j + n - k] && vec[n - k][i + k][j]))
					{
						vec[n][i][j] = true;
						break;
					}
				}
			}
		}
	}
	return vec[N][0][0];
}

int main()
{
	{
		string s1 = "great", s2 = "rgeat";
		cout << solution1(s1, s2) << endl;	//true
	}
	{
		string s1 = "abcde", s2 = "caebd";
		cout << solution1(s1, s2) << endl;	//false
	}
	{
		string s1 = "a", s2 = "a";
		cout << solution1(s1, s2) << endl;	//true
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值