---
# System prepended metadata

title: '[Leetcode #572.](https://leetcode.com/problems/subtree-of-another-tree/) Subtree of Another Tree'
tags: [Easy, Binary tree]

---

# [Leetcode #572.](https://leetcode.com/problems/subtree-of-another-tree/) Subtree of Another Tree
 
###### tags:`Binary tree` `Easy`

## Problem

Given the roots of two binary trees `root` and `subRoot`, return true if there is a subtree of root with the same structure and node values of `subRoot` and `false` otherwise.

A subtree of a binary tree `tree` is a tree that consists of a node in `tree` and all of this node's descendants. The tree `tree` could also be considered as a subtree of itself.

### Sample Input/Output

**Example 1**
![](https://i.imgur.com/KXGTd0k.png)


```javascript
Input: root = [3,4,5,1,2], subRoot = [4,1,2]
Output: true
```

**Example 2**
![](https://i.imgur.com/KsOGQb3.png)

```javascript
Input: root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
Output: false
```


<br>

:::spoiler **Optimal Space & Time Complexity**

```!
Time O(MN) | Space O(M+N) -  where M is the number of nodes in the subRoot, where N is the number of nodes in the tree
```
:::



<hr/>

## Solutions

### Official 

**Recursive**

```python=
class Solution:
    def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:

        # Check for all subtree rooted at all nodes of tree "root"
        def dfs(node):

            # If this node is Empty, then no tree is rooted at this Node
            # Thus "tree rooted at node" cannot be same as "rooted at subRoot"
            # "tree rooted at subRoot" will always be non-empty (constraints)
            if node is None:
                return False

            # If "tree rooted at node" is identical to "tree at subRoot"
            elif is_identical(node, subRoot):
                return True

            # If "tree rooted at node" was not identical.
            # Check for tree rooted at children
            return dfs(node.left) or dfs(node.right)

        def is_identical(node1, node2):

            # If any one Node is Empty, both should be Empty
            if node1 is None or node2 is None:
                return node1 is None and node2 is None

            # Both Nodes Value should be Equal
            # And their respective left and right subtree should be identical
            return (node1.val == node2.val and
                    is_identical(node1.left, node2.left) and
                    is_identical(node1.right, node2.right))

        # Check for node rooted at "root"
        return dfs(root)
```

- Time complexity: `O(MN)`
    For every **N** `node` in the tree, we check if the tree rooted at `node` is identical to `subRoot`. This check takes `O(M)` time, where **M** is the number of nodes in `subRoot`. Hence, the overall time complexity is `O(MN)`.
    
- Space complexity: `O(M+N)`
    There will be at most **N** recursive call to `dfs` ( or `isSubtree`). Now, each of these calls will have **M** recursive calls to `isIdentical`. Before calling `isIdentical`, our call stack has at most `O(N)` elements and might increase to `O(N+M)` during the call. After calling `isIdentical`, it will be back to at most `O(N)` since all elements made by `isIdentical` are popped out. Hence, the maximum number of elements in the call stack will be **M+N**.

<br>


---

### Everyone's

**Recursive**

:::spoiler 月

```javascript=
// Time: O(t+s) || Space: O(t+s)
// t, s are each the number of nodes.
 const isSubtree = (root, subRoot) => {
    if(!subRoot) return true;
    if(!root) return false;
    if(root.val === subRoot.val){
        if(isSameTree(root,subRoot)) return true;
    }
    return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot)
    };
const isSameTree = (root, subRoot) => {
    if(!root && !subRoot) return true;
    if(!root || !subRoot) return false;
    if(root.val !== subRoot.val) return false;
    return isSameTree(root.left, subRoot.left) && isSameTree(root.right, subRoot.right)
}
```
:::

<br>

:::spoiler 東
```javascript=
/* Time O(m * n) | Space(log(m)+log(n)) 
   m is the number of root node
   n is the number of subroot node
*/ 
var isSubtree = function(root, subRoot) {
    if(!subRoot) return true;
    if(!root) return false;
    if(isSameTree(root, subRoot)) return true;
    return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
};

const isSameTree = function(p, q) {
    if(!p && !q) return true;
    else if(!p || !q) return false;
    else if(p.val === q.val){
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
    return false;
};
```
:::

<br>

:::spoiler YC

```javascript=
/*
    time: O(m*n) - where n is the number of nodes in the tree, m is the number of nodes in the subRoot.
    space: O(m+n); - where m is the number of nodes in root, where n is the number of nodes in subRoot
*/

var isSubtree = function(root, subRoot) {
  if(!root){
    return false;
  }
  
  if(isSame(root, subRoot)){
    return true;
  }
  
  return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
  
};

function isSame(root, subRoot){
  if(!root || !subRoot){
    return !root && !subRoot;
  }
  
  if(root.val !== subRoot.val) {
    return false;
  }

  return isSame(root.left, subRoot.left) && isSame(root.right, subRoot.right);
}
```
:::

<br>

**Iterative + Recursive**

:::spoiler 東
```javascript=
/* Time O(m * n) | Space(m + c) ~= Space(m + log(n)) 
   m is the number of root node
   n is the number of subroot node
   c is the depth of subroot node
*/ 
var isSubtree = function(root, subRoot) {
    const queue = [];
    queue.push(root);
    while(queue.length !== 0){
        const currNode = queue.shift();
        if(isSameTree(currNode, subRoot)) return true;
        if(currNode.left) queue.push(currNode.left);
        if(currNode.right) queue.push(currNode.right);
    }
    return false;
};

const isSameTree = function(p, q) {
    if(!p && !q) return true;
    else if(!p || !q) return false;
    else if(p.val === q.val){
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
    return false;
};

```
:::


<br>

:::spoiler Hao (need fix)

```javascript=
function BfsTraverser(root) {
  this.queue = [root];

  this.next = function() {
    const node = this.queue.shift();
    
    node.left && this.enqueue(node.left);
    node.right && this.enqueue(node.right);

    return node;
  }

  this.enqueue = function(node) {
    this.queue[this.queue.length] = node;
  }
}

var isSubtree = function(root, subRoot) {
  const isSubtreeInner = (treeA, treeB) => {
    let shouldLoop = true;
    let res = false;

    while (shouldLoop) {
      const [valA, valB] = [treeA.next()?.val, treeB.next()?.val];

      if (valA === valB && valA === undefined) {
        shouldLoop = false
        res = true;
      } else if (valA !== valB) {
        shouldLoop = false
      }
    };

    return res;
  };

  let res = false;
  const tree = new BfsTraverser(root);

  while (tree.queue.length) {
    const node = tree.next();

    if (node.val === subRoot.val) {
      if (isSubtreeInner(new BfsTraverser(node), new BfsTraverser(subRoot))) res = true;
    }
  }

  return res;
};
```
:::


---

## Supplement / Discussion
Approach 2: String Matching
![](https://i.imgur.com/h0EBGiP.png)

- 黑色數字：是 Preorder 經過時紀錄的
- <span class="red">紅</span>色數字：是 Inorder 經過時紀錄的
- <span class="green">綠</span>色數字：是 Postorder 經過時紀錄的

> [複習 pre-order, in-order, post-order](https://hackmd.io/t65f76ofTj-IQjh7xzViWA)

```javascript=
/*
    Time O(M+N) | Space O(M+N) -  where M is the number of nodes in the subRoot, where N is the number of nodes in the tree
*/

var isSubtree = function(root, subRoot) {
  const subRootStr = convertString(subRoot)
  const rootStr = convertString(root)
  return rootStr.includes(subRootStr);
};

function convertString(root, rootStr = ""){
    if (!root) return rootStr;

    rootStr += root.val
    rootStr = convertString(root.left, rootStr)
    rootStr += root.val
    rootStr = convertString(root.right, rootStr)
    rootStr += root.val

    return rootStr
}
```


## Reference
https://ithelp.ithome.com.tw/articles/10280308


<style>
.red {
  color: red;
}
    
.green {
  color: green;
}
</style>