题目地址:
https://www.acwing.com/problem/content/35/
输入两棵二叉树 A A A, B B B,判断 B B B是不是 A A A的子结构。我们规定空树不是任何树的子结构。
数据范围:
每棵树的节点数量
[
0
,
1000
]
[0,1000]
[0,1000]。
先对两棵树进行先序序列化,序列化完成之后做一次KMP匹配即可。注意这里是“子结构”而不是子树,所以空节点虽然仍然需要序列化(这可以保证结构吻合),但是匹配的时候需要让空节点可以匹配任意字符。代码如下:
#include <string>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
bool hasSubtree(TreeNode *pRoot1, TreeNode *pRoot2) {
// 特判一下空树
if (!pRoot2) return false;
string s1, s2;
// 对两棵树做先序序列化
dfs(pRoot1, s1);
dfs(pRoot2, s2);
s1 = " " + s1;
s2 = " " + s2;
auto ne = build_ne(s2);
return kmp(s1, s2, ne);
}
bool kmp(string &s, string &p, vector<int> &ne) {
int n = s.size() - 1, m = p.size() - 1;
for (int i = 1, j = 0; i <= n; i++) {
// 如果是p的空节点则自动匹配成功
while (j && s[i] != p[j + 1] && p[j + 1] != '$') j = ne[j];
if (s[i] == p[j + 1] || p[j + 1] == '$') j++;
if (j == m) return true;
}
return false;
}
vector<int> build_ne(string &s) {
int n = s.size() - 1;
vector<int> ne(n + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[i] != s[j + 1]) j = ne[j];
if (s[i] == s[j + 1]) j++;
ne[i] = i < n && s[i + 1] != s[j + 1] ? j : ne[j];
}
return ne;
}
void dfs(TreeNode *x, string &s) {
if (!x) {
s += "$,";
return;
}
s += to_string(x->val) + ',';
dfs(x->left, s);
dfs(x->right, s);
}
};
时空复杂度 O ( n A + n B ) O(n_A+n_B) O(nA+nB), n A , n B n_A,n_B nA,nB分别是两棵树的节点个数。