力扣87.扰乱字符串

题目:biubiu
题意:给定两个字符串,要求就是只能对一个字符串进行分割,分割成两个子串,然后两个子串可以交换,例如s1分割成s11和s12两个子串,两个子串可以s11+s12也可以s12+s11,两个子串可以继续相同的操作,问,现在s1==s2是否为真。
对字符串的操作其实非常简单,就是切割然后判断是否交换,其子串也可以继续切割,就涉及到了递归。
官方题解代码:

#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<map>
#include<unordered_map>
#include<stack>
#include<algorithm>
using namespace std;
/*
class Solution {
public:
	bool judge(string s1, string s2,int x) {
		if (s1.size() == 1) {
			if (s1 == s2)
				return true;
			else
				return false;
		}
		int y=x+1;
		int i;
		for ( i = 1; i < s2.size(); i++) {
			if (y == s1.size())
				break;
			if (s1[y] == s2[i]) {
				y++;
			}
			else {
				break;
			}
		}
		string s3, s4;
		s3 = s1.substr(0, x);
		s4 = s2.substr(i, x);
		//cout << s3 << "****" << s4 << endl;
		if (s3==s4||isScramble(s3, s4))
		{
			if (y == s1.size())
				return true;
			s3 = s1.substr(y);
			s4 = s2.substr(y);
			//cout << s3 << "##$##" << s4 << endl;
			if (s3==s4||isScramble(s3, s4))
				return true;
			else
				return false;
		}
		else {
			return false;
		}
	}
	bool isScramble(string s1, string s2) {
		if (s1 == s2)
			return true;
		for (int i = 0; i < s1.size(); i++) {
			if (s1[i] != s2[i]) {
				s1 = s1.substr(i);
				s2 = s2.substr(i);
				break;
			}
		}
		for (int i = 0; i < s1.size(); i++) {
			if (s1[i] == s2[0]) {
				//cout << "*" << i << endl;
				if (judge(s1, s2, i))
					return true;
			}
		}
		for (int i = 0; i < s1.size(); i++) {
			if (s2[i] == s1[0]) {
				//cout << "*" << i << endl;
				if (judge(s2, s1, i))
					return true;
			}
		}
		return false;
	}
};*/

class Solution {
    
    
private:
	// 记忆化搜索存储状态的数组
	// -1 表示 false,1 表示 true,0 表示未计算
	int memo[30][30][31];
	string s1, s2;

public:
	bool checkIfSimilar(int i1, int i2, int length) {
    
    
		unordered_map<int, int> freq;
		for (int i = i1; i < i1 + length; ++i) {
    
    
			++freq[s1[i]];
		}
		for (int i = i2; i < i2 + length; ++i) {
    
    
			--freq[s2[i]];
		}
		if (any_of(freq.begin(), freq.end(), [](const auto& entry) {
    
    return entry.second != 0; })) {
    
    
			return false;
		}
		return true;
	}

	// 第一个字符串从 i1 开始,第二个字符串从 i2 开始,子串的长度为 length,是否和谐
	bool dfs(int i1, int i2, int length) {
    
    
		if (memo[i1][i2][length]) {
    
    
			return memo[i1][i2][length] == 1;
		}

		// 判断两个子串是否相等
		if (s1.substr(i1, length) == s2.substr(i2, length)) {
    
    
			memo[i1][i2][length] = 1;
			return true;
		}

		// 判断是否存在字符 c 在两个子串中出现的次数不同
		if (!checkIfSimilar(i1, i2, length)) {
    
    
			memo[i1][i2][length] = -1;
			return false;
		}

		// 枚举分割位置
		for (int i = 1; i < length; ++i) {
    
    
			// 不交换的情况
			if (dfs(i1, i2, i) && dfs(i1 + i, i2 + i, length - i)) {
    
    
				memo[i1][i2][length] = 1;
				return true;
			}
			// 交换的情况
			if (dfs(i1, i2 + length - i, i) && dfs(i1 + i, i2, length - i)) {
    
    
				memo[i1][i2][length] = 1;
				return true;
			}
		}

		memo[i1][i2][length] = -1;
		return false;
	}

	bool isScramble(string s1, string s2) {
    
    
		memset(memo, 0, sizeof(memo));
		this->s1 = s1;
		this->s2 = s2;
		return dfs(0, 0, s1.size());
	}
};


int main() {
    
    
	string s1, s2;
	while (cin >> s1 >> s2) {
    
    
		Solution s;
		cout << s.isScramble(s1, s2) << endl;
	}
	return 0;
}

官方代码很好理解,递归切割然后标记,动态规划。这个题对字符串的操作其实很简单,就是切割然后是否交换位置,但是在最开始的时候没有想到这种方法,并且其实在题目描述中,描述的很清楚,已经给了递归的思路,并且,两个字符串匹配就要求字符的顺序相同,字符的数量相同,因此递归的时候只需要对切割的长度进行遍历即可。
发现自己思维打不开,其实这道题看过题解之后很好理解,就是切割,如果其子串可以匹配,那么这个字符串也就可以匹配,它的状态来源于子串的结果,并且子串的状态只有两种,交换,不变,s1分割成s11、s12,s2分割成s21、s22,那么不变的情况就是s11和s21进行匹配(s12-s22),同样,交换就是s11和s22进行匹配,子串的匹配不就和s1和s2匹配的问题相同,要找到解决问题的实际状态。

猜你喜欢

转载自blog.csdn.net/qq_43840681/article/details/121419112