572. Subtree of Another Tree


Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants. The tree s could also be considered as a subtree of itself.

Example 1:
Given tree s:

     3
    / \
   4   5
  / \
 1   2
Given tree t:
   4 
  / \
 1   2
Return true, because t has the same structure and node values with a subtree of s.

Example 2:
Given tree s:

     3
    / \
   4   5
  / \
 1   2
    /
   0
Given tree t:
   4
  / \
 1   2
Return false.


Solution


Approach #1 Using Preorder Traversal [Accepted]

Algorithm

We can find the preorder traversal of the given tree and , given by, say and respectively(represented in the form of a string). Now, we can check if is a substring of .

But, in order to use this approach, we need to treat the given tree in a different manner. Rather than assuming a value for the childern of the leaf nodes, we need to treat the left and right child as a and value respectively. This is done to ensure that the doesn't become a substring of even in cases when isn't a subtree of .

You can also note that we've added a '#' before every considering every value. If this isn't done, the trees of the form s:[23, 4, 5] and t:[3, 4, 5] will also give a true result since the preorder string of the t("23 4 lnull rull 5 lnull rnull") will be a substring of the preorder string of s("3 4 lnull rull 5 lnull rnull"). Adding a '#' before the node's value solves this problem.

Preorder_null

Preorder_lnull_rnull

Complexity Analysis

  • Time complexity : . A total of nodes of the tree and nodes of tree are traversed. Assuming string concatenation takes time for strings of length and indexOf takes .

  • Space complexity : . The depth of the recursion tree can go upto for tree and for tree in worst case.


Approach #2 By Comparison of Nodes [Accepted]

Algorithm

Instead of creating an inorder traversal, we can treat every node of the given tree as the root, treat it as a subtree and compare the corresponding subtree with the given subtree for equality. For checking the equality, we can compare the all the nodes of the two subtrees.

For doing this, we make use a function traverse(s,t) which traverses over the given tree and treats every node as the root of the subtree currently being considered. It also checks the two subtrees currently being considered for their equality. In order to check the equality of the two subtrees, we make use of equals(x,y) function, which takes and , which are the roots of the two subtrees to be compared as the inputs and returns True or False depending on whether the two are equal or not. It compares all the nodes of the two subtrees for equality. Firstly, it checks whether the roots of the two trees for equality and then calls itself recursively for the left subtree and the right subtree.

The follwowing animation depicts an abstracted view of the process:

!?!../Documents/572_Subtree.json:1000,563!?!

Complexity Analysis

  • Time complexity : . In worst case(skewed tree) traverse function takes time.

  • Space complexity : . The depth of the recursion tree can go upto . refers to the number of nodes in .


Analysis written by: @vinod23