【问题标题】:Check if a binary tree is a mirror image or symmetric检查二叉树是镜像还是对称
【发布时间】:2012-01-16 05:19:45
【问题描述】:

测试树是否对称的基本算法是什么。因为它是一棵二叉树,我会假设它是排序的递归定义

正式问题如下:

如果二叉树的左右子树是相同的镜像,即二叉树是对称的,则二叉树是自身的镜像。 最好用几个例子来解释这一点。

  1
 / \
2   2

是的

   1
  / \
 2   2
  \
   3

错误

     1
   /   \
  2     2
 / \   / \
4   3 3   4

是的

       1
     /   \
    2     2 
   / \   / \
  3   4 3   4

错误

       1
     /   \
    2     2
   /       \
  3         3

是的

在选择的编程语言中,定义 BTree 类/C 结构和关联方法以检查树是否为镜像。对于静态类型语言,您可以假设节点值都是整数。

Class/structure definition
BTree {
  BTree left;
  BTree right;
  int value;
}

假设调用者跟踪树的根,并在其上调用函数 isMirror()。

此外,如果定义一个类,如果数据元素不可公开访问,请确保提供无参数构造函数和 getter/setter 方法。

【问题讨论】:

    标签: algorithm language-agnostic data-structures binary-tree


    【解决方案1】:

    如何在以下函数上调用 mirrorEquals(root.left, root.right) :-

    boolean mirrorEquals(BTree left, BTree right) {
      if (left == null || right == null) return left == null && right == null;
      return left.value == right.value
         && mirrorEquals(left.left, right.right)
         && mirrorEquals(left.right, right.left);
    }
    

    基本比较左子树和倒转右子树,在根上画一条假想的倒转线。

    【讨论】:

    • 你可以用一个if (left == null || right == null) return false;替换第二个和第三个条件句
    • 不,你不能:如果它们都为空,你需要返回true
    • @comingstorm,我说的是以前版本的代码,其中第一个条件是if (left == null && right == null) return true;,第二个是我建议的。
    • 考虑到他发帖的速度和简洁程度,这家伙真是个天才。
    • 二叉搜索树永远不可能是对称的。
    【解决方案2】:

    解决方案 1 - 递归:

    bool isMirror(BinaryTreeNode *a, BinaryTreeNode *b)
    {
        return (a && b) ?  
            (a->m_nValue==b->m_nValue 
            && isMirror(a->m_pLeft,b->m_pRight) 
            && isMirror(a->m_pRight,b->m_pLeft)) :  
        (a == b);
    }
    bool isMirrorItselfRecursively(BinaryTreeNode *root) 
    {
        if (!root)
            return true;
    
        return isMirror(root->m_pLeft, root->m_pRight);
    }
    

    解决方案 2 - 迭代:

    bool isMirrorItselfIteratively(BinaryTreeNode *root) 
    {
        /// use single queue
        if(!root) return true;
        queue<BinaryTreeNode *> q;
        q.push(root->m_pLeft);
        q.push(root->m_pRight);
        BinaryTreeNode *l, *r;
        while(!q.empty()) {
            l = q.front();
            q.pop();
            r = q.front();
            q.pop();
            if(l==NULL && r==NULL) continue;
            if(l==NULL || r==NULL || l->m_nValue!=r->m_nValue) return false;
            q.push(l->m_pLeft);
            q.push(r->m_pRight);
            q.push(l->m_pRight);
            q.push(r->m_pLeft);
        }
    
        return true;
    }
    

    【讨论】:

    • 嗨Herohuyongtao,我可能错了,但迭代解决方案中的以下行可能会抛出NPE l 或r 为空。 if(l==NULL || r==NULL || l->m_nValue!=r->m_nValue) 返回假;我已将您的代码包含在博客中 - k2code.blogspot.in/2014/10/…
    • @kinshuk4 能否提供导致 NPE 错误的用户案例?我会测试它。
    【解决方案3】:

    Java 中的递归和迭代解决方案使用上述方法

    递归

    public Boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
    
        return isSymmetricInternal(root.left, root.right);
    }
    
    private Boolean isSymmetricInternal(TreeNode leftNode,
            TreeNode rightNode) {
    
        boolean result = false;
    
        // If both null then true
        if (leftNode == null && rightNode == null) {
            result = true;
        }
    
        if (leftNode != null && rightNode != null) {
            result = (leftNode.data == rightNode.data)
                    && isSymmetricInternal(leftNode.left, rightNode.right)
                    && isSymmetricInternal(leftNode.right, rightNode.left);
        }
    
        return result;
    }
    

    迭代使用LinkedList作为队列

    private Boolean isSymmetricRecursive(TreeNode root) {
        boolean result = false;
    
        if (root == null) {
            return= true;
        }
    
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root.left);
        queue.offer(root.right);
    
        while (!queue.isEmpty()) {
            TreeNode left = queue.poll();
            TreeNode right = queue.poll();
    
            if (left == null && right == null) {
    
                result = true;
    
            }
            else if (left == null || 
                    right == null || 
                    left.data != right.data) {
                // It is required to set result = false here
                result = false;
                break;
            }
    
            else if (left != null && right != null) {
                queue.offer(left.left);
                queue.offer(right.right);
    
                queue.offer(left.right);
                queue.offer(right.left);
            }
        }
    
        return result;
    }
    

    测试用例

        @Test
    public void testTree() {
    
        TreeNode root0 = new TreeNode(1);
        assertTrue(isSymmetric(root0));
        assertTrue(isSymmetricRecursive(root0));
    
        TreeNode root1 = new TreeNode(1, new TreeNode(2), new TreeNode(2));
        assertTrue(isSymmetric(root1));
        assertTrue(isSymmetricRecursive(root1));
    
        TreeNode root2 = new TreeNode(1,
                new TreeNode(2, null, new TreeNode(3)), new TreeNode(2));
        assertFalse(isSymmetric(root2));
        assertFalse(isSymmetricRecursive(root2));
    
        TreeNode root3 = new TreeNode(1, new TreeNode(2, new TreeNode(4),
                new TreeNode(3)), new TreeNode(2, new TreeNode(3),
                new TreeNode(4)));
        assertTrue(isTreeSymmetric(root3));
        assertTrue(isSymmetricRecursive(root3));
    
        TreeNode root4 = new TreeNode(1, new TreeNode(2, new TreeNode(3),
                new TreeNode(4)), new TreeNode(2, new TreeNode(3),
                new TreeNode(4)));
        assertFalse(isSymmetric(root4));
        assertFalse(isSymmetricRecursive(root4));
    }
    

    树节点

    public class TreeNode {
    
    int data;
    
    public TreeNode left;
    public TreeNode right;
    
    public TreeNode(int data){
        this(data, null, null);
    }
    
    public TreeNode(int data, TreeNode left, TreeNode right)
    {
        this.data = data;
        this.left = left;
        this.right = right;
    }
    }
    

    【讨论】:

      【解决方案4】:

      @gvijay 的递归解法很清楚,这里是迭代解法。

      从上到下检查树的每一行,看看这些值是否是回文。如果他们都是那么,是的,它是一面镜子。您需要实现一种算法来访问每一行并包含稀疏树的空值。在伪代码中:

      boolean isMirror(BTree tree) {
        foreach (List<Integer> row : tree.rows() {
          if (row != row.reverse()) return false;
        }
        return true;
      }
      

      诀窍是设计算法来迭代树的行,同时考虑到稀疏树应该有空值作为占位符。这个 Java 实现看起来不错:

      public static boolean isMirror(BTree root) {
        List<BTree> thisRow, nextRow;
        thisRow = Arrays.asList(root);
        while (true) {
          // Return false if this row is not a palindrome.
          for (int i=0; i<thisRow.size()/2; i++) {
            BTree x = thisRow.get(i);
            BTree y = thisRow.get(thisRow.size()-i-1);
            if ((x!=null) && (y!=null)
                && (x.value != y.value))
              return false;
            if (((x==null) && (y!=null))
                || (x!=null) && (y==null))
              return false;
          }
          // Move on to the next row.
          nextRow = new ArrayList<BTree>();
          for (BTree tree : thisRow) {
            nextRow.add((tree==null) ? null : tree.lt);
            nextRow.add((tree==null) ? null : tree.rt);
          }
          boolean allNull = true;
          for (BTree tree : nextRow) {
            if (tree != null) allNull = false;
          }
          // If the row is all empty then we're done.
          if (allNull) return true;
          thisRow = nextRow;
        }
      }
      

      【讨论】:

        【解决方案5】:

        编辑

        正如 cmets 中所指出的,我的第一个算法版本在某些输入上失败了。我不会重新发明轮子,我只会使用@gvijay 正确算法提供 Python 答案。一、二叉树的表示:

        class BTree(object):
            def __init__(self, l, r, v):
                self.left  = l
                self.right = r
                self.value = v
            def is_mirror(self):
                return self._mirror_equals(self.left, self.right)
            def _mirror_equals(self, left, right):
                if left is None or right is None:
                    return left is None and right is None
                return (left.value == right.value
                        and self._mirror_equals(left.left, right.right)
                        and self._mirror_equals(left.right, right.left))
        

        我使用问题中的所有示例树测试了上述代码返回不正确结果的树,如 cmets 中所述。现在所有情况下的结果都是正确的:

        root1 = BTree(
            BTree(None, None, 2),
            BTree(None, None, 2),
            1)
        root1.is_mirror() # True
        
        root2 = BTree(
            BTree(None, BTree(None, None, 3), 2),
            BTree(None, None, 2),
            1)
        root2.is_mirror() # False
        
        root3 = BTree(
            BTree(
                BTree(None, None, 4),
                BTree(None, None, 3),
                2),
            BTree(
                BTree(None, None, 3),
                BTree(None, None, 4),
                2),
            1)
        root3.is_mirror() # True
        
        root4 = BTree(
            BTree(
                BTree(None, None, 3),
                BTree(None, None, 4),
                2),
            BTree(
                BTree(None, None, 3),
                BTree(None, None, 4),
                2),
            1)
        root4.is_mirror() # False
        
        root5 = BTree(
            BTree(BTree(None, None, 3), None, 2),
            BTree(None, BTree(None, None, 3), 2),
            1)
        root5.is_mirror() # True
        
        root6 = BTree(BTree(None, None, 1), None, 1)
        root6.is_mirror() # False
        
        root7 = BTree(BTree(BTree(None, None, 1), None, 2), None, 1)
        root7.is_mirror() # False
        

        【讨论】:

        • 嗯,尽管此算法会错误地将以下树检测为镜像BTree(BTree(None, None, 1), None, 1),或任何其他其有序值列表为回文的树。例如BTree(BTree(BTree(None, None, 1), None, 2), None, 1).
        • @maerics,你是对的。感谢您指出了这一点;我已经编辑了我的答案。
        【解决方案6】:

        这是每个 gvijay 的 C++ 解决方案

        bool isMirrorTree(BTnode* LP, BTnode* RP)
        {
            if (LP == NULL || RP == NULL) // if either is null check that both are NULL
            { 
                return ( LP == NULL && RP == NULL );
            } 
            // check that data is equal and then recurse
            return LP->data == RP->data && 
                   isMirrorTree( LP->left, RP->right ) && 
                   isMirrorTree( LP->right, RP->left );
        }
        

        【讨论】:

          【解决方案7】:

          下面是关于C-COde的解决方案

          isMirror(root)
          { 
          Symmetric(root->left, root->right);
          }
          
          Symmetric(root1,root2)
          {
           if( (root1->left EX-NOR root2->right) && (root1->right EX-NOR root2->left) && (root1->value==root2->value) )        
          //exnor operation will return true if either both present or both not present 
          // a EX-NOR b =(!a && !b) || (a && b))
                  {
              Symmetric(root1->left, root2->right);
              Symmetric(root1->right, root2->left);
                  }    
          else return false;
          }
          

          【讨论】:

            【解决方案8】:

            如果有人需要 Swift 版本,这里有。

            另一种方法是仅反转其中一个子树,并以直接的方式比较两个结果子树。

            func compareTrees(left: TreeNode?, right: TreeNode?) -> Bool {
                var res = false
                if left == nil && right == nil {return true}
                if left != nil && right != nil {
                    res = left!.val == right!.val &&
                          compareTrees(left!.left, right: right!.left) &&
                          compareTrees(left!.right, right: right!.right)
                }
                return res
            }
            
            func invertTree(node: TreeNode?) {
                if node == nil {return}
            
                var tmp = node!.left
                node!.left = node!.right
                node!.right = tmp
            
                invertTree(node!.left)
                invertTree(node!.right)
            }
            
            // and run it as:
            if root == nil {print("Y")}
            invertTree(root!.right)
            compareTrees(root!.left, right: root!.right) ? print("Y") : print("N")
            

            【讨论】:

              【解决方案9】:

              方法略有不同。

              如何对二叉树进行中序遍历,将所有内容存储在字符串/数组等数据结构中。

              遍历完成后,检查数组中的元素是否形成回文。 在空间方面效率不高(递归需要 O(log(n)),这种方法需要 O(n)),但这也可以。

              【讨论】:

              • 这不起作用。考虑层序遍历为 {1,2,3,3,#,2,#} 的树,其中 # 表示空值。
              【解决方案10】:

              在 python 中使用稍微不同的方法的迭代解决方案。使用 queue1 按照从左到右的顺序存储左孩子,使用 queue2 按照从右到左的顺序存储右孩子并比较是否相等。

              def isSymmetric(root):
                  if not root:
                      return True
                  if not (root.left or root.right):
                      return True
                  q1 = collections.deque([root.left])
                  q2 = collections.deque([root.right])
                  while q1 and q2:
                      n1 = q1.popleft()
                      n2 = q2.popleft()
                      if n1 is None and n2 is None:
                          continue
                      if (n1 is None) ^ (n2 is None):
                          return False
                      if n1.val != n2.val:
                          return False
                      q1.append(n1.left)
                      q1.append(n1.right)
                      q2.append(n2.right)
                      q2.append(n2.left)
                  if not (q1 and q2):
                      return True
                  return False
              

              【讨论】:

                【解决方案11】:

                使用python

                # Definition for a binary tree node.
                # class TreeNode:
                #     def __init__(self, x):
                #         self.val = x
                #         self.left = None
                #         self.right = None
                
                class Solution:
                    def isSymmetric(self, root):
                        """
                        :type root: TreeNode
                        :rtype: bool
                        """
                        def helper(root1, root2):
                            if not root1 and not root2: return True
                            if not root1 or not root2: return False            
                            if root1.val != root2.val: return False
                            if helper(root1.left, root2.right): return helper(root1.right, root2.left)
                            return  False
                        return helper(root, root)
                

                【讨论】:

                  【解决方案12】:

                  我想我会在 Python 中添加一个解决方案,有些人可能会发现它比其他方法更容易理解。这个想法是:

                  1. +1 添加到左孩子返回的值。
                  2. -1 添加到右孩子返回的值中。
                  3. l+r返回给父母

                  因此,如果l+r == 0 用于树中的任何节点,则锚定在该节点的子树是对称的。因此整个树只有当l+r == 0 在根时才对称。

                  def check(root):
                      l = check(root.left)+1 if root.left else 0
                      r = check(root.right)-1 if root.right else 0
                      return l+r
                  
                  def is_symmetric(root):
                      return root is not None and check(root) == 0
                  

                  【讨论】:

                  • 这行不通。您的想法似乎是检查结构对称性(忽略节点值)。但是,您正在检查两个子树的左右节点数之间的差异是否相同,符号反转。此外,如果您使用左节点扩展叶节点“3”,您将得到 OP 的第二个示例的误报。
                  【解决方案13】:
                  public class SymmetricTree {
                  
                      /**
                       * @param args
                       */
                      public static void main(String[] args) {
                          // TODO Auto-generated method stub
                          //int[] array = {1,2,2,3,4,4,3};
                          /*
                           *                  1
                           *                 / \
                           *                /   \
                           *               /     \
                           *              2       2
                           *             / \     / \
                           *            /   \   /   \
                           *           3     4 4     3
                           * 
                           * */
                          //int[] array = {1,2};
                          BinaryTree bt=new BinaryTree();
                          bt.data=1;
                          bt.left = new BinaryTree(2);
                          bt.right = new BinaryTree(2);
                          bt.left.right = new BinaryTree(3);
                          bt.right.right = new BinaryTree(3);
                          //bt=BinaryTree.buildATree(bt, array);
                          System.out.print(isSymmetric(bt));
                          BinaryTree.inOrderTraversal(bt);
                      }
                      public static boolean isSymmetric(BinaryTree root){
                          if(root==null)
                              return true;
                          return isSymmetricLR(root.left,root.right);
                      }
                      public static boolean isSymmetricLR(BinaryTree left, BinaryTree right){
                          if(left == null && right == null)
                              return true;
                          if(left!=null && right!=null)
                              return (left.data == right.data) &&
                                      (isSymmetricLR(left.left, right.right)) &&
                                      (isSymmetricLR(left.right, right.left));
                          return false;
                      }
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    使用队列,因为我觉得递归有点难。

                    bool isSymmetric(TreeNode* root) {
                        queue<TreeNode*> q;
                        q.push(root);
                        q.push(root);
                        while(q.empty()==false){
                            TreeNode* a = q.front();
                            q.pop();
                            TreeNode* b = q.front();
                            q.pop();
                            if(a->val != b->val){
                                return false;
                            }
                             if(a->left == nullptr and b->right != nullptr)
                                return false;
                            if(a->left != nullptr and b->right == nullptr)
                                return false;
                            if(a->right != nullptr and b->left == nullptr)
                                return false;
                            if(a->right == nullptr and b->left != nullptr)
                                return false;
                            if(a->left != nullptr and b->right != nullptr){
                                q.push(a->left);
                                q.push(b->right); 
                            }
                            if(a->right != nullptr and b->left != nullptr){
                                q.push(a->right);
                                q.push(b->left);
                            }`enter code here`
                        }
                        return true;
                    }
                    

                    【讨论】:

                      【解决方案15】:

                      java脚本解决方案怎么样

                      使用的算法

                      araay = ["10" , "2", "2", "#", "1", "1", "#"] 让我们把它分解成每个步骤

                      step 1 = ["10"]
                      step 2 = [ "2", "2" ]
                      step 3 = ["#", "1", "1", "#"]
                      

                      检查除第一步以外的每个步骤的镜像

                      让我们进行第 3 步。 step 3 = ["#", "1", "1", "#"] 把它从中间分成2个数组

                      step 3 1 = ["#", "1" ]
                      step 3 2 = ["1", "#"]
                      
                      

                      现在反转步骤 3 2

                      step 3 2 = ["1", "#"]
                      

                      现在检查步骤 3 2 是否等于步骤 3 1

                      每一步都做上面的事情

                      如果都是镜像,那么二叉树就是镜像

                      const Input = ["10" , "2", "2", "#", "1", "1", "#"];
                      function isEqual(a,b)
                      {
                        // if length is not equal
                        if(a.length!=b.length)
                         return false;
                        else
                        {
                        // comapring each element of array
                         for(var i=0;i<a.length;i++)
                         if(a[i] !== b[i]){
                          return false;
                         }
                          return true;
                        }
                      }
                      
                      // Response 
                      let symetric = true ;
                      let stepSymetric = true ;
                      let mirror = true ;
                      // length of input 
                      const length = Input.length ;
                      // const length = 31 ;
                      
                      // lets create binary tree from it
                      
                      const totalSteps =
                            Math.log(length + 1)/Math.log(2) ;
                      
                      // check for symetric binary tree
                      function checkInt(n) { return parseInt(n) === n };
                       symetric = checkInt(totalSteps);
                      
                      //now check for mirror
                      let goneArrayLength = 0 ;
                      for (let i = 0; i < totalSteps; i++) { 
                        const cStep = Math.pow(2,i);
                        
                        const stepArray = [];
                        // console.log(goneArrayLength);
                        
                        // now update the step array 
                        const start = goneArrayLength ;
                        const end =  goneArrayLength + cStep ;
                        
                        for (let j = start; j < end; j++) {
                          stepArray.push(Input[j])
                        }
                        
                        console.log(stepArray);
                        // Now we have each step lets find they are mirror image or not
                        // check for even length
                        if(stepArray.length%2 !== 0 && i !== 0){
                          stepSymetric = false ;
                        }
                        const partitation = stepArray.length / 2 ;
                        const leftArray = stepArray.slice(0,partitation);
                        const rightArray = stepArray.slice(partitation , partitation * 2);
                        // console.log("leftArray");
                        // console.log(leftArray);
                        // console.log("rightArray");
                        // console.log(rightArray);
                        function mirrorCheck (){
                          let check = false;
                          if(cStep === 1){
                            return true ;
                          }
                          let array1 = leftArray;
                          let array2 = rightArray.reverse();
                          // console.log("first");
                          // console.log(array1);
                          // console.log("second");
                          // console.log(array2);
                         let equal = isEqual(array1 , array2)
                         // console.log(equal);
                          check = true ;
                          if(!equal){
                            // console.log("Noooooooooooooooo")
                            check = false ;
                          }
                          
                          return check;
                        }
                        let mirrorC = mirrorCheck();
                        
                        if(!mirrorC){
                          mirror = false;
                        }
                        goneArrayLength = goneArrayLength + cStep ;
                      }
                      console.log(mirror + " " + symetric + " " + stepSymetric )
                      
                      if(mirror && symetric && stepSymetric ){
                        console.log("Mirror Image");
                        
                      }
                      else{
                        console.log("Not mirror image")
                      }
                      // console.log(isSymetric);
                      // console.log(totalSteps);

                      【讨论】:

                        【解决方案16】:

                        我不是很有经验(只在公司工作了一年),但在我看来,这可以通过使用 S=recursion 来解决

                        例如:

                        MYTREECLASS B1= new MYTREECLASS();
                        MYTREECLASS B2= new MYTREECLASS();
                        B1= OriginalTree;
                        B2=OriginalTRee;
                        Boolean CHECK(MYTREECLASS, MYTREECLASS)
                        {
                        if (B1.Node = B2.Node)
                        then (
                        CHECK(B1.Left, B2.Right);
                        CHECK(B1.Right,B2.Left)
                        )
                        elseIf(b1.Left==null or b2.right...blah blah ,,)
                        return False)
                        else return False,
                        

                        如果匹配则返回 true。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2017-04-14
                          • 2021-08-24
                          • 2015-04-23
                          • 2019-11-05
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-05-16
                          相关资源
                          最近更新 更多