https://leetcode.cn/problems/binary-tree-level-order-traversal/solutions/2774207/102-er-cha-shu-de-ceng-xu-bian-li-by-jok-9c45
226. 翻转二叉树
https://leetcode.cn/problems/invert-binary-tree/solutions/2774554/226-fan-zhuan-er-cha-shu-by-joker-ek4-c5xs
递归写法
前序
1 2 3 4 5 6 7 8 9 10
| class Solution { public: TreeNode *invertTree(TreeNode *root) { if(root == NULL) return NULL; swap(root->left, root->right); invertTree(root->left); invertTree(root->right); return root; } };
|
后序
1 2 3 4 5 6 7 8 9 10
| class Solution { public: TreeNode *invertTree(TreeNode *root) { if(root == NULL) return NULL; invertTree(root->left); invertTree(root->right); swap(root->left, root->right); return root; } };
|
中序
1 2 3 4 5 6 7 8 9 10
| class Solution { public: TreeNode *invertTree(TreeNode *root) { if(root == NULL) return NULL; invertTree(root->left); swap(root->left, root->right); invertTree(root->left); return root; } };
|
迭代前后中非统一写法记不清楚的,不实用
前序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: TreeNode *invertTree(TreeNode *root) { stack<TreeNode *> st; if (root != NULL) st.push(root);
while (!st.empty()) { TreeNode *node = st.top(); st.pop(); swap(node->left, node->right); if (node->right) st.push(node->right);
if (node->left) st.push(node->left); } return root; } };
|
后序这个不是本题的题解,只是一个遍历顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: vector<int> postorderTraversal(TreeNode* root) { stack<TreeNode*> st; vector<int> result; if (root == NULL) return result; st.push(root); while (!st.empty()) { TreeNode* node = st.top(); st.pop(); result.push_back(node->val); if (node->left) st.push(node->left); if (node->right) st.push(node->right); } reverse(result.begin(), result.end()); return result; } };
|
中序这个不是本题的题解,只是一个遍历顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: vector<int> inorderTraversal(TreeNode* root) { vector<int> result; stack<TreeNode*> st; TreeNode* cur = root; while (cur != NULL || !st.empty()) { if (cur != NULL) { st.push(cur); cur = cur->left; } else { cur = st.top(); st.pop(); result.push_back(cur->val); cur = cur->right; } } return result; } };
|
迭代前中后统一写法
node
和root
的区别
同时最最重要的,递归里面root是遍历所有节点的,相当于cur。
但是迭代里面root就是根节点,就处理一次。然后就用node结点从栈或者队列里面取元素了。相当于node是遍历所有节点,相当于cur。
因此进左右子树的时候,递归是这样子的,用的root.left
和root.right
1 2
| invertTree(root->left); invertTree(root->right);
|
因此进左右子树的时候,迭代是这样子的,用的node.left
和node.right
1 2
| if (node->right) st.push(node->right); if (node->left) st.push(node->left);
|
递归和迭代易混淆类似代码区别,判不判空
个人理解:递归里面第一句一般都是这句话,因为这是递归结束终止条件,因此空结点的判断都交给下一层来判断并返回。所以
1
| if (root == NULL) return root;
|
所以进入下一层的时候允许空姐点进去,因为一进入立刻就返回,不会有影响。
1 2
| invertTree(root->left); invertTree(root->right);
|
但是迭代不一样,无论你是用栈来迭代还是用队列来层序
都要先判断是否为空,不为空才能压入栈或者队列
用栈迭代前中后序遍历统一写法里面
对根节点的判断
1
| if (root != NULL) st.push(root);
|
对左右结点的判断
1 2
| if (node->right) st.push(node->right); if (node->left) st.push(node->left);
|
用队列层序遍历里面也适合迭代一样的,先判空
1
| if (root != NULL) que.push(root);
|
1 2
| if (node->left) que.push(node->left); if (node->right) que.push(node->right);
|
前序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public: TreeNode *invertTree(TreeNode *root) { stack<TreeNode *> st; if (root != NULL) st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node != NULL) { st.pop(); if (node->right) st.push(node->right); if (node->left) st.push(node->left); st.push(node); st.push(NULL); } else { st.pop(); node = st.top(); st.pop(); swap(node->left, node->right); } } return root; } };
|
后序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: TreeNode *invertTree(TreeNode *root) { stack<TreeNode *> st; if (root != NULL) st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node != NULL) { st.pop(); st.push(node); st.push(NULL); if (node->right) st.push(node->right); if (node->left) st.push(node->left); } else { st.pop(); node = st.top(); st.pop(); swap(node->left, node->right); } } return root; } };
|
中序
但使用迭代方式统一写法的中序是可以的。为什么这个中序就是可以的呢,因为这是用栈来遍历,而不是靠指针来遍历,避免了递归法中翻转了两次的情况,
个人理解:
好像是因为递归返回的时候通过根节点到此时根节点的右子树,但是此时的,根节点的右子树是之前已经被处理过的根节点的左子树
而迭代不一样,迭代开始就访问了右,中,左结点。并且把他们的地址都放到了st栈里面。所以到处理左,中,右的时候,这个时候右结点的地址就是原来的右节点的地址,没有改变过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public: TreeNode *invertTree(TreeNode *root) { stack<TreeNode *> st; if (root != NULL) st.push(root); while (!st.empty()) { TreeNode *node = st.top(); if (node != NULL) { st.pop(); if (node->right) st.push(node->right); st.push(node); st.push(NULL); if (node->left) st.push(node->left); } else { st.pop(); node = st.top(); st.pop(); swap(node->left, node->right); } } return root; } };
|
层序写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public: TreeNode *invertTree(TreeNode *root) { queue<TreeNode *> q; if (root != NULL) q.push(root); while (!q.empty()) { int size = q.size(); for (int i = 0; i < size; i++) { TreeNode *node = q.front(); q.pop(); swap(node->left, node->right); if(node->left) q.push(node->left); if(node->right) q.push(node->right); } } return root; } };
|
这道题目想了一会,看到弹幕说用层序加栈类似括号匹配一般判断,但是自己还是不会。算是不管了
就记住carl的思路和讲解得了
个人经验总结:二叉树一般都是后序。一般收集孩子的信息,想上一层返回的都需要后续便利
递归写法
https://leetcode.cn/problems/symmetric-tree/solutions/2786926/101-dui-cheng-er-cha-shu-by-joker-ek4-1b2p
这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。
这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历)
还有栈还有队列的写法。
明天再卡吧