参考链接
- https://leetcode-cn.com/problems/scramble-string/
题目描述
使用下面描述的算法可以扰乱字符串 s 得到字符串 t :
如果字符串的长度为 1 ,算法停止
如果字符串的长度 > 1 ,执行下述步骤:
在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。
给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。
解题思路
题目很友善地写出了递归思路,所以按照这个流程稍微改改就行了。先明确一点,我们只需要变化s1,判断其通过若干变换能否等于s2即可。实际上就是穷举,暴力求解,从s1的第一位开始分割,分割后再确定是否交互左右子串,接着判断左右子串和s2的左右子串(子串的长度根据s1来分就行)是否能够通过变换相等,如此递归。有几种递归结束的条件:1)如果s1等于s2,返回true;2)如果s1的长度为1,s1不等于s2,返回false;3)如果交换前或交换后任一可以变换相等,返回true。还需要加上状态表来记录之前的结果,否则会超时。
当然,还可以一开始就判断s1和s2中的字符个数是否一致,不一致直接返回false,本题略。
代码
class Solution {
unordered_map <string, bool> memo;
public:
bool isScramble(string s1, string s2) {
if(memo.count(s1 + '_' + s2) != 0)
{
return memo[s1 + '_' + s2];
}
if(s1 == s2)
{
memo[s1 + '_' + s2] = true;
return true;
}
else if(s1.size() == 1)
{
memo[s1 + '_' + s2] = false;
return false;
}
bool do_it = false;
bool not_do = false;
for(int i = 1; i < s1.size(); i ++)
{
do_it = isScramble(s1.substr(i, s1.size()), s2.substr(0, s1.size() - i)) && isScramble(s1.substr(0, i), s2.substr(s1.size() - i, s1.size()));
not_do = isScramble(s1.substr(0, i), s2.substr(0, i)) && isScramble(s1.substr(i, s1.size()), s2.substr(i, s1.size()));
if(do_it || not_do)
{
memo[s1 + '_' + s2] = true;
return true;
}
}
memo[s1 + '_' + s2] = false;
return false;
}
};