【问题标题】:Determine if 2 binary trees are similar判断两棵二叉树是否相似
【发布时间】:2021-08-01 10:19:28
【问题描述】:

我无法确定每个级别的节点数是否相同。到目前为止的问题和我的代码如下提供

如果树的每一层的节点数相同,则将两棵二叉树称为大小相似

鉴于以下情况:

class TreeNode {
    String nodeValue;
    TreeNode rightNode;
    TreeNode leftNode;

    TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
        this.nodeValue = nodeValue;
        this.rightNode = rightNode;
        this.leftNode = leftNode;
    }
}

这个问题的目的是编写一个函数来验证两棵树的大小是否相似。

如果正确则该函数应返回 true,否则返回 false

我的代码:

//implemented with java
class TreeNode {
    String nodeValue;
    TreeNode rightNode;
    TreeNode leftNode;

    TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
        this.nodeValue = nodeValue;
        this.rightNode = rightNode;
        this.leftNode = leftNode;
    }

    //function to return size of node, i.e. number of children
    int nodeSize() {
        //if node has both left and right child node
        if (this.rightNode.nodeValue != null && this.leftNode.nodeValue != null) {
            return 2;
        //if node has no child nodes
        } else if (this.rightNode.nodeValue == null && this.leftNode.nodeValue == null) {
            return 0;
        //if node just has either left or right child node
        } else {
            return 1;
        }
    }

    boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
        //if both nodes have no child nodes
        if (firstTree.nodeSize() == 0 && secondTree.nodeSize() == 0) {
            return true;
        }

        //if both nodes have at least 1 child node
        if (firstTree.nodeSize() != 0 && secondTree.nodeSize() != 0) {
            return ((firstTree.nodeSize() == secondTree.nodeSize()) &&
                    similarSizedTrees(firstTree.leftNode, secondTree.leftNode) &&
                    similarSizedTrees(firstTree.leftNode, secondTree.rightNode));
        }

        //
        return false;
    }
}

我遇到的问题是我的代码没有考虑每个级别的节点数。

【问题讨论】:

  • 如果问题是2个二叉树是否相似。那么为什么我们要检查每一层树的节点数呢?
  • 大小相似的树和相似的树,这两种是不同的。
  • @BadhanSen 我认为这只是预先给出的相似性的定义,无论它多么直观。这就是我们所说的在每个级别上具有相同节点数的两次尝试。

标签: java algorithm tree binary-tree nodes


【解决方案1】:

想法是统计每一层的节点数,然后检查两棵树的总层数是否相同。如果不相同则返回 false 否则检查每个级别计数并比较值。如果两个值相等则返回真,否则返回假。

class TreeNode {
    String nodeValue;
    TreeNode rightNode;
    TreeNode leftNode;

    TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
        this.nodeValue = nodeValue;
        this.rightNode = rightNode;
        this.leftNode = leftNode;
    }
    
    
    public void countLevelNode(TreeNode root, int level, int[] sum) {
        if(root == null) return;
        sum[level]++;
        countLevelNode(root.leftNode, level + 1, sum);
        countLevelNode(root.rightNode, level + 1, sum);
        
    } 
    boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
        int[] countFirstTreeNode = new int[1000];
        int[] countSecondTreeNode = new int[1000];
        int totalLevelofFirstTree = 0;
        int totalLevelofSecondTree = 0;

        countLevelNode(firstTree, totalLevelofFirstTree, countFirstTreeNode);
        countLevelNode(secondTree, totalLevelofSecondTree, countSecondTreeNode);

        if(totalLevelofFirstTree != totalLevelofSecondTree){
            return false;
        }
        else{
            for(int i = 0; i < totalLevelofFirstTree; i++){
                if(countFirstTreeNode[i] != countSecondTreeNode[i]){
                    return false;
                }
            }
            return true;
        }
    }
}

【讨论】:

  • 是否有理由在similarSizedTrees() 之外初始化全局变量?多次调用该函数会导致不确定的行为,因为数组在第一次调用后永远不会重新初始化。
  • 没有具体原因。您可以在similarSizedTrees() 方法中进行初始化,也可以。
  • 感谢@ShaanK 指出此案。我更新了代码。请看一下。
  • 看起来不错,您可以始终将变量定义保留为全局,但我喜欢您将所有内容都移动到本地的方式。
【解决方案2】:

这是一个使用递归的解决方案:

int find_height(TreeNode t){
    return (t == null)? 0 : 1 + Math.max(find_height(t.leftNode), find_height(t.rightNode));
}

boolean is_similar_tree(TreeNode l, TreeNode r){
    int l_height = find_height(l);
    int r_height = find_height(r);

    if(l_height != r_height)
        return false;

    int[] l_height_sums = new int[l_height];
    int[] r_height_sums = new int[r_height];

    is_similar_tree_helper(l, l_height_sums, l_height);
    is_similar_tree_helper(r, r_height_sums, r_height);

    return Arrays.equals(l_height_sums, r_height_sums);
}

void is_similar_tree_helper(TreeNode t, int[] table, int height){
    if(t == null || height == 0)
        return;

    table[height - 1]++;

    is_similar_tree_helper(t.leftNode, table, height - 1);
    is_similar_tree_helper(t.rightNode, table, height - 1);
}

【讨论】:

    【解决方案3】:

    可以在这里找到几个解决方案:https://www.techiedelight.com/check-if-two-binary-trees-are-identical-not-iterative-recursive/

    这是根据您的代码定制的上述链接中显示的递归函数。

     boolean similarSizedTrees(TreeNode x, TreeNode y) {
            // bottom of tree reached
            if (x == null && y == null) {
                return true;
            }
            // both trees are non-empty and the value of their root node matches,
            // recur for their left and right subtree
            return (x != null && y != null) && (x.key == y.key) &&
                        similarSizedTrees(x.left, y.left) &&
                        similarSizedTrees(x.right, y.right);
        }
    

    编辑:您还可以使用两个全局 int 变量来保持每个级别的节点计数,每棵树一个,当您遍历树时递增每个变量,然后在继续下一个级别之前将它们一起比较。

    【讨论】:

      【解决方案4】:

      您的基于递归的方法行不通,因为下一级的节点数不受每个子节点从哪个节点的影响。您可以修改您的方法以使用简单的级别顺序遍历。

      (编辑:添加@Piotr 的解释)
      基本思想是计算每个级别的节点。在示例图片中,第 1 层有 1 个节点,第 2 层有 2 个节点,第 3 层有 3 个节点,最后有第 4 层有 1 个节点。这两棵树的这些数字完全相同,即使它们不完全相同。该算法正在计算每个级别的这些计数,如果发现差异,则返回 False。否则,如果两棵树相似,它最终返回 True。 (我不是很精通Java,但是你可以很容易地翻译算法):

      def similar(firstTree, secondTree):
      
          queue1, queue2 = queue(firstTree), queue(secondTree) # create queues for traversal
          # each queue stores all nodes in a given level 
          while queue1 and queue2:
              if len(queue1)!=len(queue2): # check base condition
                  return False
      
              i = 0
              while i<len(queue1): # append all next level nodes for tree 1
                  node = queue1.pop()
                  if node.left:
                      queue1.insert(node.left)
                  if node.right:
                      queue1.insert(node.right)
                  i += 1
      
              i = 0
              while i<len(queue2): # append all next level nodes for tree 2
                  node = queue2.pop()
                  if node.left:
                      queue2.insert(node.left)
                  if node.right:
                      queue2.insert(node.right)
                  i += 1
      
          if queue1 or queue2:
              return False # either tree couldn't complete traversal because of different heights
      
          return True
      

      【讨论】:

      • 我认为这段代码是正确的,但可能仍然不清楚它对这个问题的作者做了什么。基本思想是计算每个级别的节点。在示例图片中,第 1 级有 1 个节点,第 2 级有 2 个节点,第 3 级有 3 个节点,最后有第 4 级有 1 个节点。这两棵树的这些数字完全相同,即使它们不完全 一样。该算法正在计算每个级别的这些计数,如果发现差异,则返回 False。否则,如果两棵树相似,则最终返回 True。
      • @Piotr 好的,谢谢。我也会在答案中包含您的解释
      猜你喜欢
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      • 2018-06-30
      • 2021-08-24
      • 2010-10-19
      相关资源
      最近更新 更多