LeetCode 572 另一个树的子树 牛客题霸 判断t1树中是否有与t2树拓扑结构完全相同的子树

给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

 

示例 1:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2
给定的树 t:

   4 
  / \
 1   2
返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。

 

示例 2:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2
    /
   0
给定的树 t:

   4
  / \
 1   2
返回 false。

 

解题思路:

DFS 暴力匹配。

这是一种最朴素的方法 —— DFS 枚举 s 中的每一个节点,判断这个点的子树是否和 t 相等。如何判断一个节点的子树是否和 t 相等呢,我们又需要做一次 DFS 来检查,即让两个指针一开始先指向该节点和 t 的根,然后「同步移动」两根指针来「同步遍历」这两棵树,判断对应位置是否相等。

 

Python代码:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
        if not s and not t:
            return True
        if not s or not t:
            return False
        return self.isSametree(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
    def isSametree(self, s, t):
        if not s and not t:
            return True
        if not s or not t:
            return False
        return s.val == t.val and self.isSametree(s.left, t.left) and self.isSametree(s.right, t.right)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Trie和AC自动机是字符串匹配的两种经典算法。Trie是一种形结构,用于存储一组字符串,常用于字符串查找、前缀匹配等场景。AC自动机是对Trie的改进,可以在多个模式串中进行高效的匹配。 PHP的Trie实现比较简单,可以用数组来模拟的结构。例如,下面是一个实现前缀匹配的Trie的示例代码: ```php class TrieNode { public $children = []; public $isEndOfWord = false; } class Trie { private $root; public function __construct() { $this->root = new TrieNode(); } public function insert(string $word) { $node = $this->root; for ($i = 0; $i < strlen($word); $i++) { $char = $word[$i]; if (!isset($node->children[$char])) { $node->children[$char] = new TrieNode(); } $node = $node->children[$char]; } $node->isEndOfWord = true; } public function search(string $word) { $node = $this->root; for ($i = 0; $i < strlen($word); $i++) { $char = $word[$i]; if (!isset($node->children[$char])) { return false; } $node = $node->children[$char]; } return $node->isEndOfWord; } public function startsWith(string $prefix) { $node = $this->root; for ($i = 0; $i < strlen($prefix); $i++) { $char = $prefix[$i]; if (!isset($node->children[$char])) { return false; } $node = $node->children[$char]; } return true; } } $trie = new Trie(); $trie->insert("hello"); $trie->insert("world"); var_dump($trie->search("hello")); // true var_dump($trie->startsWith("hell")); // true var_dump($trie->search("worlds")); // false ``` Go语言也有Trie的实现,可以使用map来模拟的结构。下面是一个Go语言实现的Trie的示例代码: ```go type TrieNode struct { Children map[byte]*TrieNode IsEndOfWord bool } type Trie struct { Root *TrieNode } func NewTrie() *Trie { return &Trie{Root: &TrieNode{Children: make(map[byte]*TrieNode)}} } func (t *Trie) Insert(word string) { node := t.Root for i := 0; i < len(word); i++ { char := word[i] if _, ok := node.Children[char]; !ok { node.Children[char] = &TrieNode{Children: make(map[byte]*TrieNode)} } node = node.Children[char] } node.IsEndOfWord = true } func (t *Trie) Search(word string) bool { node := t.Root for i := 0; i < len(word); i++ { char := word[i] if _, ok := node.Children[char]; !ok { return false } node = node.Children[char] } return node.IsEndOfWord } func (t *Trie) StartsWith(prefix string) bool { node := t.Root for i := 0; i < len(prefix); i++ { char := prefix[i] if _, ok := node.Children[char]; !ok { return false } node = node.Children[char] } return true } trie := NewTrie() trie.Insert("hello") trie.Insert("world") fmt.Println(trie.Search("hello")) // true fmt.Println(trie.StartsWith("hell")) // true fmt.Println(trie.Search("worlds")) // false ``` AC自动机是基于Trie的一种改进,可以在多个模式串中进行高效的匹配。它的基本思想是将多个模式串构建成一棵Trie,并在每个节点上维护一个Fail指针,指向它的最长后缀节点。在匹配过程中,利用Fail指针进行快速跳转,避免重复匹配。 下面是一个Go语言实现的AC自动机的示例代码: ```go type ACNode struct { Children map[byte]*ACNode Fail *ACNode IsEndOfWord bool } type AC struct { Root *ACNode } func NewAC() *AC { return &AC{Root: &ACNode{Children: make(map[byte]*ACNode)}} } func (a *AC) Insert(word string) { node := a.Root for i := 0; i < len(word); i++ { char := word[i] if _, ok := node.Children[char]; !ok { node.Children[char] = &ACNode{Children: make(map[byte]*ACNode), Fail: a.Root} } node = node.Children[char] } node.IsEndOfWord = true } func (a *AC) Build() { queue := make([]*ACNode, 0) for _, child := range a.Root.Children { child.Fail = a.Root queue = append(queue, child) } for len(queue) > 0 { parent := queue[0] queue = queue[1:] for char, child := range parent.Children { fail := parent.Fail for fail != a.Root && fail.Children[char] == nil { fail = fail.Fail } if fail.Children[char] != nil { child.Fail = fail.Children[char] } else { child.Fail = a.Root } queue = append(queue, child) } } } func (a *AC) Search(text string) map[string]bool { result := make(map[string]bool) node := a.Root for i := 0; i < len(text); i++ { char := text[i] for node != a.Root && node.Children[char] == nil { node = node.Fail } if node.Children[char] != nil { node = node.Children[char] } if node.IsEndOfWord { result[text[i-len(word)+1:i+1]] = true } for fail := node.Fail; fail != a.Root && fail.IsEndOfWord; fail = fail.Fail { result[text[i-len(word)+len(word)-len(fail.Fail)+1:i+1]] = true } } return result } ac := NewAC() ac.Insert("he") ac.Insert("she") ac.Insert("his") ac.Insert("hers") ac.Build() fmt.Println(ac.Search("ushers")) // map[hers:true she:true he:true] ``` AC自动机的实现比Trie稍微复杂一些,但是它在字符串匹配方面的性能比Trie更优秀。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值