• 剑指 Offer 26. 树的子结构


    思路

    方法一:如果B的先序序列是A的先序序列的子序列,并且B的中序序列也是A的中序序列的子序列,则B是A的子结构。这种方法比较暴力。

    方法二:对A的每一个结点和B进行比较(这里可以使用先序遍历):

      如果A->val == B->val,则A的左子树和右子树也要和B对应的左子树右子树相同。

      如果A->val != B->val,则A的左子树或者右子树要和B相同。

    注意:因为树A中可能有值相同的结点,所以必须对A的每一个结点都和B进行比较。比如如下测试样例:

    [4,2,3,4,5,6,7,8,9]
    [4,8,9]

    方法二的代码实现

     1 /**
     2  * Definition for a binary tree node.
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     //先序遍历,判断A的每一个结点
    13     bool isSubStructure(TreeNode* A, TreeNode* B) {
    14         if(B == NULL || A == NULL)
    15             return false;
    16         if(check(A, B)) 
    17             return true;
    18         return isSubStructure(A->left, B) || isSubStructure(A->right, B);
    19     }
    20 
    21     bool check(TreeNode* A, TreeNode* B) {
    22         if(B == NULL) {
    23             return true;
    24         }
    25 
    26         if(A == NULL) {
    27             return false;
    28         }
    29 
    30         if(A->val == B->val) {
    31             return check(A->left, B->left) && check(A->right, B->right);
    32         } else {
    33             return false;
    34         }
    35     }
    36 
    37 };

    如果A中不含值相同的结点时,可以不需要对A先序遍历每个节点进行判断。可以直接用如下代码判断:

     1 /**
     2  * Definition for a binary tree node.
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     bool isSubStructure(TreeNode* A, TreeNode* B) {
    13         if(B == NULL)
    14             return false;
    15         return check(A, B);
    16     }
    17 
    18     //只有A中不含重复元素的时候,才能用此方法判断
    19     bool check(TreeNode* A, TreeNode* B) {
    20         if(B == NULL) {
    21             return true;
    22         }
    23 
    24         if(A == NULL) {
    25             return false;
    26         }
    27 
    28         if(A->val == B->val) {
    29             return check(A->left, B->left) && check(A->right, B->right);
    30         } else {
    31             return check(A->left, B) || check(A->right, B);
    32         }
    33     }
    34 };

    复杂度分析

    时间复杂度 O(MN) : 其中 M,N分别为树 A 和 树 B 的节点数量;先序遍历树 A 占用 O(M) ,每次调用 check(A, B) 判断占用 O(N) 。
    空间复杂度 O(M) : 当树 A 和树 B 都退化为链表时,递归调用深度最大。当 M≤N 时,遍历树 A与递归判断的总递归深度为 M ;当 M>N时,最差情况为遍历至树 A 叶子节点,此时总递归深度为 M。

  • 相关阅读:
    选择排序
    冒泡排序
    排序介绍
    如何在服务器搭建JavaWeb项目环境(阿里轻量级)
    SSM整合配置文件
    如何删干净MySQL数据库
    spring概述
    Git简单命令
    第六天——读操作(二)
    第六天——文件操作(一)
  • 原文地址:https://www.cnblogs.com/FengZeng666/p/13872342.html
Copyright © 2020-2023  润新知