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 1:  By Comparison of Nodes 

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

This isSame function also a dfs preorder traversal. 


class Solution{
  public boolean isSubtree(TreeNode s, TreeNode t){
    if (s == null){
      return false;
    }
    
    if (t == null){
      return true;
    }
    
    if (isSame(s, t)){
      return true;
    }
    
    return isSubtree(s.left, t) || isSubtree(s.right, t);
  }
  private boolean isSame(TreeNode s, TreeNode t){
    if (s == null && t == null) return true;
    
    if (s == null || t == null) return false;
    
    if (s.val != t.val) return false;
    
    return isSame(s.left, t.left) && isSame(s.right, t.right);
  }
}






  Time complexity : O(m*n)

O(m∗n). In worst case(skewed tree) traverse function takes O(m*n)


Space complexity : O(n)

O(n). The depth of the recursion tree can go upto n

n refers to the number of nodes in s



Solution 2: 
Using Preorder Traversal

We can find the preorder traversal of the given tree s and t, given by, say 
s preorder and t preorder respectively(represented in the form of a string). Now, we can check if t preorder  is a substring of s preorder
.
Because String::contains indeed isn't linear time.
Check the source code and you'll see the naive O(nm) algorithm



class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
      return ser(s).contains(ser(t));
    }
    public String ser(TreeNode root){
      StringBuilder result = new StringBuilder();
      serialize(root, result);
      return result.toString();
    }
    private void serialize(TreeNode cur, StringBuilder result){
      if(cur == null){
        result.append(",#");
        return;
      }
      
      result.append("," + cur.val);
      serialize(cur.left, result);
      serialize(cur.right, result);
    }
}

 

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.

 , 3, 4, 1, #, #, 2, 0, #, #, #, 5, #, #

, 4, 1, #, #, 2, #, #

, 3, 4, 1, #, #, 2, #, #, 5, #, #