1. 暴力求解,深度优先
解题思路:时间复杂度O(s*t)其中s是树的结点个数,t是子树的结点个数。空间复杂度O(max(ds,dt))其中ds是树的深度,dt是子树的深度 |
---|
- 我们先对整个树深度优先遍历
- 每个结点都与子树的根节点进行比对
- 如果对上了,就以当前结点为根节点,进行和子树的深度优先遍历,看看是否一一对应
- 对应上就返回true,没对应上就继续深度优先遍历。直到整个树遍历完成
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null && subRoot == null) return true;
else if(root == null || subRoot == null) return false;
else return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot)||isSameTree(root,subRoot);
}
public boolean isSameTree(TreeNode root,TreeNode subRoot){
if(root == null && subRoot == null) return true;
if(root == null || subRoot == null) return false;
if(root.val == subRoot.val){
return isSameTree(root.left,subRoot.left) && isSameTree(root.right,subRoot.right);
}
return false;
}
}
2. KMP算法进行串匹配
解题思路:时间复杂度O(s+t),空间复杂度O(s+t) |
---|
- 生成两颗树的遍历序列,以类似如下的形式:(下面形式是广度(层序)遍历序列,需要额外空间辅助,所以我们放弃)
- 为了效率和更少的空间,我们使用广度优先遍历。那么就需要两个不同的值,来表示某结点左子树为空,和右子树为空的情况。
- 同样为了效率,我们不使用字符串比较,选用int型容器,比如int型的链表来生成匹配串
- 那么null如何来表示呢?
- 我们可以规定两个值,来分别表示左子树为null和右子树为null的情况
- 这里我选择先找到树中最大值max,然后令max+1表示左子树为空情况,max+2表示右子树为空情况
- 生成两颗树的匹配串后,让大树作为主字符串,要匹配的子树作为要匹配的子串,改编KMP算法,如果匹配成功,说明树中可以匹配到子树
代码:leetcode的特色之一就是,更优的算法,有时因为使用程序自带的特殊容器(比如Java中的List),因为这些容器初始化比较耗时间,反而耗时更高。但是实际工作场景,一旦数据量起来,肯定是这个算法优于上面的暴力解法的。 |
---|
class Solution {
List<Integer> sOrder = new ArrayList<Integer>();
List<Integer> tOrder = new ArrayList<Integer>();
int maxElement, lNull, rNull;
public void getMaxElement(TreeNode t) {
if (t == null) return;
maxElement = Math.max(maxElement, t.val);
getMaxElement(t.left);
getMaxElement(t.right);
}
public void getDfsOrder(TreeNode t, List<Integer> tar) {
if (t == null) return;
tar.add(t.val);
if (t.left != null) getDfsOrder(t.left, tar);
else tar.add(lNull);
if (t.right != null) getDfsOrder(t.right, tar);
else tar.add(rNull);
}
public boolean isSubtree(TreeNode s, TreeNode t) {
maxElement = Integer.MIN_VALUE;
getMaxElement(s);
getMaxElement(t);
lNull = maxElement + 1;
rNull = maxElement + 2;
getDfsOrder(s, sOrder);
getDfsOrder(t, tOrder);
return kmp();
}
public boolean kmp() {
int sLen = sOrder.size(), tLen = tOrder.size();
int[] fail = new int[tOrder.size()];
fail[0] = 0;
for (int i = 1, j = 0; i < tLen; ++i) {
while (j > 0 && !(tOrder.get(i).equals(tOrder.get(j)))) j = fail[j-1];
if (tOrder.get(i).equals(tOrder.get(j))) ++j;
fail[i] = j;
}
for (int i = 0, j = 0; i < sLen; ++i) {
while (j > 0 && !(sOrder.get(i).equals(tOrder.get(j)))) j = fail[j-1];
if (sOrder.get(i).equals(tOrder.get(j))) ++j;
if (j == tLen) return true;
}
return false;
}
}