一、对称二叉树
1、题目链接:leedcodeT101--对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
2、题目思路:
解决二叉树类问题,首先要明确自己要用哪一种遍历二叉树的方式,遍历二叉树的形式有三种:1、先序遍历--中左右,2、中序遍历--左中右,3、后序遍历--左右中。遍历二叉树的方法有两种:第一种是 DFS--深度优先搜索,第二种是 BFS--广度优先搜索。代码的实现方式也有两种:第一种为函数递归实现,第二种为 迭代法实现,各有所长,具体问题具体分析地辩证地使用。
解决对称二叉树类问题,我们的遍历形式一定是->后序遍历--左右中,判断两个子节点是对称了的之后我们把这个消息传给父节点,从下到上层层传递,最后返回true,我们就可以断定这个二叉树是对称二叉树。因为我们们要从最底层向上遍历着来判断,若底层中有一点不符合规定我们就返回false。那么我们如何实现一层一层地判断呢,答案是-->广度优先搜索的思想,我们用一个队列queue就可以实现了
代码是卡哥写的-->我是复制过来的
这个是递归形式的代码,若不用递归,就要用队列来实现了
(1)递归实现
class Solution { public: bool compare(TreeNode* left, TreeNode* right) { // 首先排除空节点的情况 if (left == NULL && right != NULL) return false; else if (left != NULL && right == NULL) return false; else if (left == NULL && right == NULL) return true; // 排除了空节点,再排除数值不相同的情况 else if (left->val != right->val) return false; // 此时就是:左右节点都不为空,且数值相同的情况 // 此时才做递归,做下一层的判断 bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右 bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左 bool isSame = outside && inside; // 左子树:中、 右子树:中 (逻辑处理) return isSame; } bool isSymmetric(TreeNode* root) { if (root == NULL) return true; return compare(root->left, root->right); } };
这里的 递归用卡式递归三步走来实现:
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
很多人看完代码之后,就会问,你为啥不加一个 if(left->val == right->val) return true呢?你想,如果二叉树得形式是[1,2,2,3],你在遍历[2,2]这一层的时候返回一个true,直接判断完了,那个3的子节点你都没判断,肯定是不正确的。
我手写了一个用queue队列来实现的代码,可能比递归的逻辑更好理解一些
(2) queue队列实现
class Solution { public: bool isSymmetric(TreeNode* root) { queue<TreeNode*>que; //使用迭代法,利用队列 if(root == nullptr) return true; //若头节点为空,则二叉树一定对称 que.push(root->left); que.push(root->right); while(!que.empty()) { TreeNode *leftNode = que.front(); que.pop(); TreeNode *rightNode = que.front(); que.pop(); if(leftNode == nullptr && rightNode == nullptr) continue; //若左右孩子为空,则一定对称,后面就不用去判断了,因为根本就没有后面没了,直接跳出本次循环,开始下一次循环,网二叉树的更下层去遍历和判断 else if(leftNode == nullptr && rightNode != nullptr) return false; else if(leftNode != nullptr && rightNode == nullptr) return false; else if(leftNode->val != rightNode->val) return false; //后面三种情况,显而易见,符合一种直接false que.push(leftNode->left); que.push(rightNode->right); que.push(leftNode->right); que.push(rightNode->left); } return true; //若判断完了整个树都没有问题,则这棵树就是对称二叉树 } };
相比递归来说,队列实现可能会稍显冗余,但逻辑和思路更加清晰
其实不止有队列,用栈stack也可以实现相同的操作,修改几行代码即可
二、重复二叉树 与 子二叉树
1、重复二叉树
有这样一种题目,题目中给你两个二叉树,要求你判断这两个二叉树是否相等
--1、题目链接:leedcodeT100--重复二叉树
--2、题目思路:
我们可以用队列queue来实现,从用迭代法广度优先搜索的方式,通过出入队进行比较的方式来判断。
队列实现:
class Solution { public: bool isSameTree(TreeNode* p, TreeNode* q) { queue<TreeNode*>que; if(p == nullptr && q == nullptr) return true; else if(p != nullptr && q == nullptr) return false; else if(p == nullptr && q != nullptr) return false; else if(p->val != q->val) return false; que.push(p->left); que.push(q->left); que.push(p->right); que.push(q->right); while(!que.empty()) { TreeNode *treeP = que.front(); que.pop(); TreeNode *treeQ = que.front(); que.pop(); if(treeP == nullptr && treeQ == nullptr) continue; //直接跳出循环,开始判断下一层 else if(treeP != nullptr && treeQ == nullptr) return false; else if(treeP == nullptr && treeQ != nullptr) return false; else if(treeP->val != treeQ->val) return false; que.push(treeP->left); que.push(treeQ->left); que.push(treeP->right); que.push(treeQ->right); } return true; } };
2、子二叉树--递归的极致艺术
--1、题目链接:leedcodeT572--另一颗树的子树
--2、题目思路:
其实我一开始是想用队列来实现的,我先在主树种搜索子树的父节点,依次向下就像重复二叉树的那种方法一样向下检查是否完全一致,直达一个逆天的测试案例击碎了我天真的幻想--->
然后我又想尝试将所有匹配的节点放到一个vector的数组里面,再 一个一个的测试,可是非常麻烦,于是我掏出了一用就废的递归大法
--3、递归实现
* Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { // 这个就是LeetCode100 题的那个函数 public boolean isSameTree(TreeNode s,TreeNode t){ // 同时为空 说明树一起到底,两树相同 if (s==null && t == null){ return true; } // 如果上面没有返回值,说明必有一个没有为空(有可能两个都不为空) if (s == null || t == null){ return false; } // 如果判断到了这一步,说明两个都不为空 // 先序遍历 自己--左 -- 右 if (s.val != t.val){ return false; } return isSameTree(s.left,t.left) && isSameTree(s.right,t.right); } public boolean isSubtree(TreeNode s, TreeNode t) { // 我s都遍历完了。你居然还没匹配上。那就返回false if (s==null){ return false; } // 短路运算符,有一个为真,返回真 return isSameTree(s,t) || isSubtree(s.left,t) || isSubtree(s.right,t); } }
思路已经写在代码中了,模拟一下就可以读懂。