[关闭]
@xmruibi 2015-02-13T04:37:06.000000Z 字数 16283 阅读 927

Tree Problem

Algorithm


Binary Tree Content:

1. The Number of Nodes in a Tree

Recursion Method: 
  1. int NodeNumRec(TreeNode node):
  2. if(node==null):
  3. return 0;
  4. return NodeNumRec(node.left)+NodeNumRec(node.right)+1;
Iterative Method:
  1. int NodeNumItr(TreeNode node):
  2. if(node==null):
  3. return 0;
  4. int nodeNum = 0;
  5. Queue<TreeNode> q = new Queue<TreeNode>();
  6. q.add(node);
  7. while(!q.isEmpty()):
  8. TreeNode qnode = q.remove();
  9. nodeNum++;
  10. if(qnode.left!=null):
  11. q.add(qnode.left);
  12. if(qnode.right!=null):
  13. q.add(qnode.right);
  14. return nodeNum;

2. The Depth of Tree:

Recursion Method:
  1. int TreeDepth(TreeNode node):
  2. if(node==null):
  3. return 0;
  4. return Math.max(TreeDepth(node.left),TreeDepth(node.right))+1;
Iterative Method:
  1. int TreeDepth(TreeNode node):
  2. if(node==null):
  3. return 0;
  4. // remember these record variables
  5. int depth = 0;
  6. int currentLevelNodes = 1;
  7. int nextLevelNodes = 0;
  8. Queue<TreeNode> q = new Queue<TreeNode>();
  9. q.add(node);
  10. while(!q.isEmpty()):
  11. TreeNode qnode = q.remove();
  12. currentLevelNodes--;
  13. if(qnode.left!=null):
  14. q.add(qnode.left);
  15. nextLevelNodes++;
  16. if(qnode.right!=null):
  17. q.add(qnode.right);
  18. nextLevelNodes++;
  19. if(currentLevelNodes==0):
  20. depth++;
  21. currentLevelNodes = nextLevelNodes;
  22. nextLevelNodes = 0;
  23. return depth;

####3. Tree Traversal:

PreOrder: - Recursion
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void preorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. list.add(node);
  6. preorder(node.left);
  7. preorder(node.right);
PreOrder: - Iterative
 关键点:要先压入右孩子,再压入左孩子,这样在出栈时会先打印左孩子再打印右孩子  
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void preorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. Stack<TreeNode> s = new Stack<TreeNode>();
  6. s.push(node);
  7. while(!s.isEmpty()):
  8. TreeNode snode = s.pop();
  9. list.add(snode);
  10. if(snode.right!=null):
  11. s.push(snode.right);
  12. if(snode.left!=null):
  13. s.push(snode.left);
InOrder: - Recursion
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void inorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. inorder(node.left);
  6. list.add(node);
  7. inorder(node.right);
InOrder: - Iterative
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void inorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. Stack<TreeNode> s = new Stack<TreeNode>();
  6. TreeNode cur = root;
  7. while(true):
  8. while(cur!=null):
  9. s.push(cur);
  10. cur = cur.left;
  11. if(!s.isEmpty()):
  12. break;
  13. cur = s.pop();
  14. list.add(cur);
  15. cur = cur.right;
PostOrder: - Recursion
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void postorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. postorder(node.left);
  6. postorder(node.right);
  7. list.add(node);
PostOrder: - Iterative
  1. List<TreeNode> list = new ArrayList<TreeNode>();
  2. void postorder(TreeNode node):
  3. if(node==null):
  4. return;
  5. Stack<TreeNode> s = new Stack<TreeNode>();
  6. Stack<TreeNode> output = new Stack<TreeNode>();
  7. s.push(node);
  8. while(!s.isEmpty()):
  9. TreeNode cur = s.pop();
  10. output.push(cur);
  11. if(cur.left!=null):
  12. s.push(cur.left);
  13. if(cur.right!=null):
  14. s.push(cur.right);
  15. while(!output.isEmpty())
  16. list.add(output.pop());

5. Level Order:

LevelOrder: - Recursion
  1. void levelTraversalRec(TreeNode root):
  2. ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>();
  3. dfs(root, 0, ret);
  4. void dfs(TreeNode root, int level, ArrayList<ArrayList<Integer>> ret):
  5. if(root == null);
  6. return;
  7. // 添加一个新的ArrayList表示新的一层
  8. if(level >= ret.size()):
  9. ret.add(new ArrayList<Integer>());
  10. ret.get(level).add(root.val); // 把节点添加到表示那一层的ArrayList里
  11. dfs(root.left, level+1, ret); // 递归处理下一层的左子树和右子树
  12. dfs(root.right, level+1, ret);
LevelOrder: - Iterative
  1. List<List<TreeNode>> res = new ArrayList<List<TreeNode>>();
  2. void LevelOrder(TreeNode root):
  3. if(root==null)
  4. return;
  5. int curLevel = 1;
  6. int nextLevel = 0;
  7. Queue<TreeNode> q = new Queue<TreeNode>();
  8. List<TreeNode> row = new ArrayList<TreeNode>();
  9. q.push(root);
  10. while(!q.isEmpty()):
  11. TreeNode qnode = q.remove();
  12. row.add(qnode);
  13. curLevel--;
  14. if(qnode.left!=null):
  15. q.push(qnode.left);
  16. nextLevel++;
  17. if(qnode.right!=null):
  18. q.push(qnode.right);
  19. nextLevel++;
  20. if(curLevel==0):
  21. curLevel = nextLevel;
  22. curLevel = 0;
  23. res.add(row);
  24. row = new ArrayList<TreeNode>();
  25. return res;

6. Convert BST to Doubly Linked List: -recursion

  1. TreeNode convertBST2DLL(TreeNode root):
  2. root = convertBST2Sub(root);
  3. while(root.left!=null):
  4. root = root.left;
  5. return root;
  6. TreeNode convertBST2Sub(TreeNode root):
  7. if(root==null||root.left==null||root.right==null):
  8. return root;
  9. TreeNode cur= null;
  10. if(root.left!=null):
  11. cur = convertBST2Sub(root.left); // get bottom left node
  12. while(cur.right!=null):
  13. cur = cur.right;
  14. cur.right = root;
  15. root.left = cur;
  16. if(root.right!=null):
  17. cur = convertBST2Sub(root.right); // get bottom right node
  18. while(cur.right!=null):
  19. cur = cur.right;
  20. cur.right = root;
  21. root.right = cur;
  22. return root;

-iterative

  1. if(root==null):
  2. return null;
  3. Stack<TreeNode> stack = new Stack<TreeNode>();
  4. TreeNode cur = root;
  5. TreeNode prev = null;
  6. TreeNode head = null;
  7. while(true):
  8. while(cur!=null):
  9. stack.push(cur);
  10. cur = cur.left;
  11. if(stack.isEmpty())
  12. break;
  13. cur = stack.pop();
  14. if(old!=null):
  15. old.right = cur;
  16. if(head==null): head = cur;
  17. old = cur;
  18. cur = cur.right;
  19. return head;

7. Level K Nodes Number:

- Recursion
  1. int getNodeNumKthLevelRec(TreeNode root, int k)
  2. if(root==null || k<1)
  3. return 0;
  4. if(k==1)
  5. return 1;
  6. int numLeft = getNodeNumKthLevelRec(root.left, k - 1); // 求root左子树的k-1层节点数
  7. int numRight = getNodeNumKthLevelRec(root.right, k - 1); // 求root右子树的k-1层节点数
  8. return numLeft + numRight;
 - Iterative
  1. int getNodeNumKthLevelRec(TreeNode root, int k)
  2. if(root==null):
  3. return 0;
  4. Queue<TreeNode> q = new Queue<TreeNode>();
  5. q.add(root);
  6. int curLevel = 1;
  7. int nextLevel = 0;
  8. int i = 0;
  9. while(!q.isEmpty()&&i<k):
  10. TreeNode cur = q.remove();
  11. curLevel--;
  12. if(cur.left!=null):
  13. q.add(cur.left);
  14. nextLevel++;
  15. if(cur.right!=null):
  16. q.add(cur.right);
  17. nextLevel++;
  18. if(curLevel==0):
  19. curLevel = nextLevel;
  20. curLevel = 0;
  21. i++;
  22. return curLevel;

8. The number of leaves:

- iterative
  1. int getLeavesNum(TreeNode root):
  2. if(root==null):
  3. return 0;
  4. if(root.left==null&&root.right==null):
  5. return 1;
  6. return getLeavesNum(root.left)+getLeavesNum(root.right);
- recursion
  1. int getLeavesNum(TreeNode root):
  2. if(root==null):
  3. return 0;
  4. int leafNum = 0;
  5. Queue<TreeNode> q = new Queue<TreeNode>();
  6. q.push(root);
  7. while(!q.isEmpty()):
  8. TreeNode node = q.pop();
  9. if(cur.left != null): // 如果有左孩子,加到队尾
  10. queue.add(cur.left);
  11. if(cur.right != null): // 如果有右孩子,加到队尾
  12. queue.add(cur.right);
  13. if(cur.left==null && cur.right==null): // 叶子节点
  14. leafNodes++;
  15. return leafNum;

9. isTheSameTree:

-recursion
  1. boolean isSameRec(TreeNode r1, TreeNode r2):
  2. if(r1==null&&r2==null)
  3. return true;
  4. else if(r1==null||r2==null)
  5. return false;
  6. if(r1!=r2)
  7. return false;
  8. return isSameRec(r1.left,r2.right)&&isSameRec(r1.right,r2.right);
-iterative
  1. boolean isSame(TreeNode r1, TreeNode r2) {
  2. // 如果两个树都是空树,则返回true
  3. if(r1==null && r2==null):
  4. return true;
  5. // 如果有一棵树是空树,另一颗不是,则返回false
  6. if(r1==null || r2==null):
  7. return false;
  8. Stack<TreeNode> s1 = new Stack<TreeNode>();
  9. Stack<TreeNode> s2 = new Stack<TreeNode>();
  10. s1.push(r1);
  11. s2.push(r2);
  12. while(!s1.isEmpty() && !s2.isEmpty()):
  13. TreeNode n1 = s1.pop();
  14. TreeNode n2 = s2.pop();
  15. if(n1==null && n2==null):
  16. continue;
  17. else if(n1!=null && n2!=null && n1.val==n2.val):
  18. s1.push(n1.right);
  19. s1.push(n1.left);
  20. s2.push(n2.right);
  21. s2.push(n2.left);
  22. else:
  23. return false;
  24. return true;

10. Balanced Tree Check:

- recursion
  1. boolean isAVLRec(TreeNode root):
  2. if(root==null)
  3. return true;
  4. if(Math.abs(getDepth(root.left),getDepth(root.right)>1)
  5. return false;
  6. return isAVLRec(root.left)&&isAVLRec(root.right);
  7. int getDepth(TreeNode node):
  8. if(node==null)
  9. return 0;
  10. return Math.max(getDepth(node.left),getDepth(node.right))+1;

11. Mirror Tree:

    - based on original tree (recursion)
  1. TreeNode mirrorRec(TreeNode root):
  2. if(root==null)
  3. return null;
  4. // TreeNode newNode = new TreeNode(root.val);
  5. TreeNode left = mirrorRec(root.left);
  6. TreeNode right = mirrorRec(root.right);
  7. // newNode.left = right;
  8. // newNode.right = left;
  9. root.left = right;
  10. root,right = left;
  11. // return newNode;
  12. return root;
    - based on original tree (iterative)
  1. void mirrorItr(TreeNode root):
  2. if(root==null)
  3. return null;
  4. Stack<TreeNode> s = new Stack<TreeNode>();
  5. s.push(root);
  6. // Stack<TreeNode> newStack = new Stack<TreeNode>();
  7. // TreeNode newRoot = new TreeNode(root.val);
  8. // newStack.push(newRoot);
  9. while(!s.isEmpty()):
  10. TreeNode cur = s.pop();
  11. // do exchange!
  12. TreeNode tmp = cur.left;
  13. cur.left = cur.right;
  14. cur.right = tmp;
  15. if(cur.right!=null)
  16. s.push(cur.right);
  17. if(cur.left!=null)
  18. s.push(cur.left);
  19. // TreeNode newCur = newStack.pop();
  20. /** if you want construct new mirror tree!
  21. if(cur.right != null):
  22. stack.push(cur.right);
  23. newCur.left = new TreeNode(cur.right.val);
  24. newStack.push(newCur.left);
  25. if(cur.left != null):
  26. stack.push(cur.left);
  27. newCur.right = new TreeNode(cur.left.val);
  28. newStack.push(newCur.right);
  29. **/

12. Last Common Anster:

    • Easy Understand Version
      if two nodes are in the differen subtree return root as the last common anster
      if two nodes are in the same left subtree or right subtree, addressing in subtree recusively
  1. TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2):
  2. if(findNodeRec(root.left,n1)):
  3. if(findNodeRec(root.right,n2))
  4. return root;
  5. else
  6. getLastCommonParentRec(root.left,n1,n2);
  7. else
  8. if(findNodeRec(root.left,n2))
  9. return root;
  10. else
  11. getLastCommonParentRec(root.right,n1,n2);
  12. boolean findNodeRec(TreeNode root, TreeNode n):
  13. if(root==null || node == null)
  14. return false;
  15. if(root == n)
  16. return true;
  17. return findNodeRec(root.left,n)||findNodeRec(root.right,n);
  18. /**
  19. boolean found = findNodeRec(root.left, node);
  20. if (!found): // 如果查找不到,再在右子树中查找
  21. found = findNodeRec(root.right, node);
  22. return found;
  23. **/
    • Concise Recursion Version:
      // get the path from root to the node
      // iterate two paths with comparing nodes difference
  1. TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2):
  2. if(root==null): return null;
  3. if(root.equals(n1)||root.equals(n2)):
  4. return root;
  5. TreeNode left = getLastCommonParentRec(root.left,n1,n2);
  6. TreeNode right = getLastCommonParentRec(root.right,n1,n2);
  7. if(left!=null&&right!=null)
  8. return root;
  9. if(left!=null)
  10. return left;
  11. return right;
  1. Non-recursion but require resurive helper function
    // get the path from root to the node
    // iterate two paths with comparing nodes difference
  1. TreeNode getLastCommonParent(TreeNode root, TreeNode n1, TreeNode n2):
  2. if(root==null||n1==null||n2==null):
  3. return null;
  4. ArrayList<TreeNode> p1 = new ArrayList<TreeNode>();
  5. ArrayList<TreeNode> p2 = new ArrayList<TreeNode>();
  6. boolean res1 = getPath(root, n1, p1);
  7. boolean res2 = getPath(root, n2, p2);
  8. if (!res1 || !res2):
  9. return null;
  10. TreeNode last = null;
  11. Iterator<TreeNode> iter1 = p1.iterator();
  12. Iterator<TreeNode> iter2 = p2.iterator();
  13. while (iter1.hasNext() && iter2.hasNext()):
  14. TreeNode tmp1 = iter1.next();
  15. TreeNode tmp2 = iter2.next();
  16. if (tmp1 == tmp2):
  17. last = tmp1;
  18. else: // 直到遇到非公共节点
  19. break;
  20. return last;
  21. boolean getPath(TreeNode root, TreeNode n, ArrayList<TreeNode> p): // backtracking
  22. if(root==null) return false;
  23. p.add(root);
  24. if(root == n)
  25. return true;
  26. boolean found = getPath(root.left,n,p);
  27. if(!found)
  28. found = getPath(root.right,n,p);
  29. if(!found)
  30. p.remove(root);
  31. return found;

####14. Max Distance between two leaves: (node1 -> root -> node2 or node1 -> nodes... -> node2)

  1. class Result: //private class for result
  2. int maxDistance;
  3. int maxDepth;
  4. public Result(): // non argument constructor
  5. public Result(int maxDistance, int maxDepth): // two argument constructor
  6. this.maxDistance = maxDistance;
  7. this.maxDepth = maxDepth;
  8. Result getMaxDistanceRec(TreeNode root):
  9. if(root == null):
  10. Result empty = new Result(0,-1);
  11. return empty;
  12. Result lmd = getMaxDistanceRec(root.left);
  13. Result rmd = getMaxDistanceRec(root.right);
  14. Result res = new Result();
  15. res.maxDepth = Math.max(lmd.maxDepth,rmd.maxDepth)+1;
  16. res.maxDistance = Math.max(lmd.maxDepth+rmd.maxDepth, Math.max(lmd.maxDistance, rmd.maxDistance));
  17. return res;

15.Binary Tree Construction:

        - preorder & inorder
  1. HashMap<Integer, Intger> inorderMap= new HashMap<Integer, Intger>();
  2. TreeNode rebuildBinaryTreeRec(List<Integer> preOrder, List<Integer> inOrder):
  3. for(int i=0;i<inOrder.size();i++):
  4. inorderMap.put(inOrder.get(i).val,i);
  5. return construct(preOrder,inOrder,0,preOrder.size()-1,0,inOrder.size()-1)
  6. TreeNode construct(List<Integer> preOrder, List<Integer> inOrder, int pstart, int pend, int istart, int iend):
  7. if(pstart>pend||istart > iend)
  8. return null;
  9. TreeNode root = preOrder.get(pstart);
  10. int index = map.get(root.val);
  11. root.left = construct(preOrder,inOrder,pstart+1,pstart+index-istart, istart,index-1);
  12. root.right = construct(preOrder,inOrder,pstart+index-istart+1,pend,index+1,iend);
  13. return root;
        - postorder & inorder
  1. HashMap<Integer, Intger> inorderMap= new HashMap<Integer, Intger>();
  2. TreeNode rebuildBinaryTreeRec(List<Integer> postOrder, List<Integer> inOrder):
  3. for(int i=0;i<inOrder.size();i++):
  4. inorderMap.put(inOrder.get(i).val,i);
  5. return construct(postOrder,inOrder,0,postOrder.size()-1,0,inOrder.size()-1)
  6. TreeNode construct(List<Integer> postOrder, List<Integer> inOrder, int pstart, int pend, int istart, int iend):
  7. if(pstart>pend||istart > iend)
  8. return null;
  9. TreeNode root = postOrder.get(pend);
  10. int index = map.get(root.val);
  11. root.left = construct(preOrder,inOrder,pstart,pstart+index-istart, istart,index-1);
  12. root.right = construct(preOrder,inOrder,pend+index-iend,pend-1,index+1,iend);
  13. return root;

16.Complete Binary Tree: 当遇到一个节点的左子树为空时,则该节点右子树必须为空,且后面遍历的节点左右子树都必须为空,否则不是完全二叉树

                -- Iterative:
  1. boolean haveNoChild(TreeNode root):
  2. if(root.left!=null||root.right!=null)
  3. return false;
  4. else
  5. return true;
  6. boolean isCompleteBT(TreeNode root):
  7. if(root == null):
  8. return false;
  9. Queue<TreeNode> q = new Queue<TreeNode>();
  10. q.add(root);
  11. boolean noChild = false; // as the flag
  12. boolean result = true;
  13. while(!q.isEmpty()):
  14. TreeNode cur = q.remove();
  15. if(noChild):
  16. if(cur.left!=null||cur.right!=null):
  17. result = false;
  18. break;
  19. else
  20. if(cur.left!=null && cur.right!=null):
  21. q.add(cur.left);
  22. q.add(cur.right);
  23. else if(cur.left!=null && cur.right==null):
  24. // 如果左子树非空但右子树为空,说明已经出现空节点,之后必须都为空子树
  25. noChild = true;
  26. q.add(cur.left);
  27. else if(cur.left==null && cur.right!=null):
  28. // 如果左子树为空但右子树非空,说明这棵树已经不是完全二叉完全树
  29. result = false;
  30. break;
  31. else
  32. noChild = true;
  33. return result;

Complete Binary Tree and Perfect Binary Tree:

  1. class Pair:
  2. int height;
  3. boolean isFull;
  4. public Pair(int height, boolean isFull): // two argument constructor
  5. this.height = height;
  6. this.isFull = isFull;
  7. boolean equalsTo(Pair obj):
  8. return this.height == obj.height && this.isFull == obj.isFull;
  9. boolean isPerfectTree(TreeNode root):
  10. return isCompleteBinaryTreeSubRec(root).isFull;
  11. boolean isCompleteBinaryTreeRec(TreeNode root):
  12. return isCompleteBinaryTreeSubRec(root).height != -1;
  13. Pair isCompleteBinaryTreeSubRec(TreeNode root):
  14. if(root == null)
  15. return Pair(0,true);
  16. Pair left = isCompleteBinaryTreeSubRec(root.left);
  17. Pair right = isCompleteBinaryTreeSubRec(root.right);
  18. // 左树满节点,而且左右树相同高度,则是唯一可能形成满树(若右树也是满节点)的情况
  19. if(left.isFull && left.height == right.height):
  20. return new Pair(1+left.height, right.isFull);
  21. // 左树非满,但右树是满节点,且左树高度比右树高一
  22. // 注意到如果其左树为非完全树,则它的高度已经被设置成-1,
  23. // 因此不可能满足第二个条件!
  24. if(right.isFull && left.height==right.height+1):
  25. return new Pair(1+left.height, false);
  26. // 其他情况都是非完全树,直接设置高度为-1
  27. return new Pair(-1, false);

17. Path Sum -Start from any node:

  1. void findSum(TreeNode head, int num, ArrayList<Integer> buffer, int level):
  2. if(head==null): return;
  3. int tmp = sum;
  4. buffer.add(head.val);
  5. for(int i=level;i>-1;i--): //check the path by buffer!
  6. tmp -= buffer.get(i);
  7. if(tmp == 0):
  8. print(buffer,i,level);
  9. ArrayList<Integer> c1 = (ArrayList<Integer>)buffer.clone();
  10. ArrayList<Integer> c2 = (ArrayList<Integer>)buffer.clone();
  11. findSum(head.left, sum, c1, level+1);
  12. findSum(head.right, sum, c2, level+1);
  13. - Start from root:
  14. ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
  15. ArrayList<ArrayList<Integer>> findSum(TreeNode root, int sum):
  16. if(root==null)
  17. return res;
  18. ArrayList<Integer> row = new ArrayList<Integer>();
  19. row.add(root.val);
  20. return findSumHelper(row, root, sum -root.val);
  21. void findSumHelper(ArrayList<Integer> row, TreeNode node, int sum):
  22. if(node == null):
  23. return;
  24. if(node.left==null&&node.right==null&&sum-node.val==0):
  25. res.add(new ArrayList<Integer>(row));
  26. return;
  27. if(node.left!=null&&node.right==null):
  28. row.add(node.left.val);
  29. findSumHelper(row, node.left, sum-node.left.val);
  30. row.remove(row.size()-1);
  31. if(node.right!=null&&node.left==null):
  32. row.add(node.right.val);
  33. findSumHelper(row, node.right, sum-node.right.val);
  34. row.remove(row.size()-1);
  35. Match Subtree:
  36. // check if the subtree is null, return true if it is null;
  37. // check if main tree contain the root node of subtree
  38. // if ant node match in two trees begin to match all node under subtree with comparing the main tree
  39. boolean containsTree(TreeNode mainRoot, TreeNode subRoot):
  40. if(subRoot == null): return true;
  41. else
  42. return subtree(mainRoot,subRoot);
  43. boolean subtree(TreeNode mainRoot, TreeNode subRoot):
  44. if(mainRoot == null):
  45. return false;
  46. if(mainRoot == subroot):
  47. if(matchTree(mainRoot, subRoot)):
  48. return true;
  49. return subtree(mainRoot.left,subRoot)||subtree(mainRoot.right,subRoot);
  50. boolean matchTree(TreeNode mainRoot, TreeNode subRoot):
  51. if(subRoot == null && mainRoot == null)
  52. return true;
  53. if(mainRoot == null || subRoot == null)
  54. return false; the main tree is empty or subtree not found
  55. if(mainRoot.val!= subRoot.val)
  56. return false;
  57. return matchTree(mainRoot.left,subRoot.left)&&matchTree(mainRoot.right,subRoot.right);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注