For the first time, there is a problem in the way of thinking: the symmetrical binary tree is not the same as the original binary tree after reversing the binary tree, instead of the left and right child nodes of a tree are equal!
class Solution { public: bool isSymmetrical(TreeNode* pRoot) { if(!pRoot) return false; bool flag = true; postorder(pRoot, flag); return flag; } void postorder(TreeNode* pRoot, bool& flag) { if(!pRoot) return; //If ((proot - > left | proot - > right) & & (proot - > Left & & proot - > left)) / / logical XOR, no corresponding operator in C + + if( (pRoot->left == nullptr)^(pRoot->right == nullptr) || (pRoot->left && pRoot->right && pRoot->left->val!=pRoot->right->val) ) { flag = false; return; } if(flag && pRoot->left) postorder(pRoot->left, flag); if(flag && pRoot->right) postorder(pRoot->right, flag); } };
After reading the problem-solving ideas in the book and glancing at the code, I realized the program myself, and the problems occurred:
1. During recursion, only adding flag will cause program errors: This is obvious. Without judging pRoot1, pRoot2 will take child nodes for them. If pRoot1/2 is empty, an error will occur. Error reporting is quite strange. It's stack overflow. Recursive calls will not go on indefinitely. It's certain that the leaf node will have the above error of "null node's child node".
2. It's not right to add a condition similar to peroot - > left in the if condition. If a node has only left subtree and no right subtree, for example [866577], it will return true in advance because no recursion is performed. Because the inertia of traversal recursion will make people get used to writing the judgment in the form of proot1 - > left.
3. The correct way is to add flag to the if condition and return it once it appears false, add pRoot1, and then recurse if pRoot2 is not empty.
4. A small point: null tree returns true
class Solution { public: bool isSymmetrical(TreeNode* pRoot) { if(!pRoot) return true; bool flag = true; biTraversal(pRoot, pRoot, flag); return flag; } //Simultaneous preorder traversal and symmetric preorder traversal of a tree void biTraversal(TreeNode* pRoot1, TreeNode* pRoot2, bool& flag) { if((!pRoot1 && !pRoot2) || (pRoot1 && pRoot2 && pRoot1->val==pRoot2->val)) { flag = true; } else { flag = false; } //if(flag && pRoot1->left && pRoot2->right) biTraversal(pRoot1->left, pRoot2->right, flag); //if(flag && pRoot1->right && pRoot2->left) biTraversal(pRoot1->right, pRoot2->left, flag); if(flag && pRoot1 && pRoot2) biTraversal(pRoot1->left, pRoot2->right, flag); if(flag && pRoot1 && pRoot2) biTraversal(pRoot1->right, pRoot2->left, flag); } };
The code in the book is much more elegant than my own:
Previously, I was forced to introduce the flag variable, because I didn't know how to set the return reasonably: when "= =" is not needed here, the return true is actually wrong. Only when the whole tree is traversed without false can the return true be returned. When the code in the book encounters false, it will no longer continue to recurse but start to return upward.
class Solution { public: bool isSymmetrical(TreeNode* pRoot) { return biTraversal(pRoot, pRoot); } //Simultaneous preorder traversal and symmetric preorder traversal of a tree bool biTraversal(TreeNode* pRoot1, TreeNode* pRoot2) { if (pRoot1==nullptr && pRoot2==nullptr) return true; //Both are nullptr if (pRoot1==nullptr || pRoot2==nullptr) return false; //Only one is nullptr if (pRoot1->val != pRoot2->val) return false; //Previously, I was forced to introduce the flag variable because I didn't know how to set the return reasonably: //It's not necessary to add = = here to return true. In fact, it's wrong to add = = here. You can only return true by traversing the entire tree return biTraversal(pRoot1->left, pRoot2->right) && biTraversal(pRoot1->right, pRoot2->left); } };