LeetCode——Subtree of Another

本文探讨了LeetCode上的经典题目572:如何判断一棵树是否为另一棵树的子树。提供了多种解决方案,包括递归比较、字符串序列化对比以及使用哈希树的方法。
LeetCode——Subtree of Another

# 572
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.

这题的目的是判断一个数是否是另一棵树的子数。从第二个例子可以看出,子树必须是完整的,不能是中间一部分,必须是叶节点。
这题显然可以用递归写,大部分树的问题,都可以用递归的方法解决。其实和前面写过的一题对称树也没大多差别。代码也很容易懂,递归的话,多使用的话,理清思路,就很容易掌握了。

  • C++
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!s) 
            return false;
        if(is_Sub(s,t)) 
            return true;
        return isSubtree(s -> left,t) || isSubtree(s -> right,t);    
    }
    bool is_Sub(TreeNode* s,TreeNode* t){
        if( !s && !t)
            return true;
        if( !s || !t)
            return false; 
        if(s -> val != t -> val)
            return false;
        return is_Sub(s -> left,t -> left) && is_Sub(s -> right,t -> right);           
        }     
};
  • Java
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        if (s == null)  
            return false;  
        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);  
    }
}
  • Python
**# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isSubtree(self, s, t):
        """
        :type s: TreeNode
        :type t: TreeNode
        :rtype: bool
        """
        if not s or not t: return not s and not t
        if self.check(s, t): return True
        return self.isSubtree(s.left, t) or self.isSubtree(s.right, t)

    def check(self, s, t):
        if not s or not t: return not s and not t
        if s.val != t.val: return False
        return self.check(s.left, t.left) and self.check(s.right, t.right)**

看到其他一些人的解法,有一种思路是对s和t两棵树分别进行序列化,各生成一个字符串,如果t的字符串是s的子串的话,就说明t是s的子树。其中一个注意的地方是,为了避免前缀,在每个节点值前面都加一个字符。代码如下。

  • C++
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        ostringstream os1, os2;  //构造一个字符串,使用ostringstream类,该类能够根据内容自动分配内存
        serialize(s, os1);
        serialize(t, os2);
        return os1.str().find(os2.str()) != string::npos;//
    }
    void serialize(TreeNode* node, ostringstream& os) { //这里的序列化使用的是前序遍历
        if (!node) os << ",#";
        else {
            os << "," << node->val;
            serialize(node->left, os);
            serialize(node->right, os);
        }
    }
};

npos可以表示string的结束位子,是string::type_size 类型的,也就是find()返回的类型。find函数在找不到指定值得情况下会返回string::npos
关于ostringstream类,也简单的描述一下。
C++提供的流(stream)包括三种类型:用于控制台输入/输出的流、用于文件操作的文件流和用于字符串处理的字符串流。

(1) 基于控制台的流

istream:用于从流中读取内容;

ostream:用于将内容写到数据流中;

iostream:用于对流进行读写,从istream和ostream派生;

它们包含在iostream头文件中。

(2) 用于文件读取/写入的文件流

ifstream:用于从文件中读取,由istream派生而来;

ofstream:用于将内容写到文件中去,由ostream派生而来;

fstream:实现文件的读写操作,有iostream派生而来;

它们包含在头文件fstream中。

(3) 基于字符串I/O操作的字符串流

istringstream:实现从字符串(string)对象中读取内容,由istream派生而来;

ostringstream:实现将内容写到字符串(string)对象中,由ostream派生而来;

stringstream:实现string对象的读写操作,由iostream派生而来;

它们包含在头文件sstream中。

这种解法的Python写法

  • Python
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isSubtree(self, s, t):
        """
        :type s: TreeNode
        :type t: TreeNode
        :rtype: bool
        """

        def preorder(node):
            if not node:
                return "$"
            return "^" + str(node.val) + "#" + preorder(node.left) + preorder(node.right)
        print preorder(s)
        print preorder(t)
        return preorder(t) in preorder(s)

还看到一种解法,使用了hash树,运行时间非常的短。但相对复杂一点,记录下来,学习一下。

  • Python
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

from hashlib import md5

class Solution(object):
    def isSubtree(self, s, t):
        def treehash(root):
            h = md5(treehash(root.left) + str(root.val) + treehash(root.right)).hexdigest() if root else ''
            hashes.append(h)
            return h
        hashes = []
        h = treehash(t)
        hashes = []
        treehash(s)
        return h in hashes

    def isSubtree(self, s, t):
        def string(root):
            return '(%d,%s,%s)' % (root.val, string(root.left), string(root.right)) if root else ''
        return string(t) in string(s)

    def isSubtree(self, s, t):
        def tuplify(root):
            return (root.val, tuplify(root.left), tuplify(root.right)) if root else None
        return str(tuplify(t)) in str(tuplify(s))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值