判断对称二叉树要比较的不是左右节点,因为有可能这不是满二叉树。二叉树是否对称,关键在于根节点的左右子树是否相互翻转的。其实要比较的是根节点的左右子树,所以无论是递归还是迭代,遍历时,先遍历外侧孩子再内侧孩子。
左右子树分四种情况讨论:
递归则先外侧再内侧,先左的左孩子与右的右孩子,再左的右孩子与右的左孩子递归
迭代则先外侧再内侧,先左的左孩子与右的右孩子,再左的右孩子与右的左孩子更新
递归法
class Solution {
public:
//递归
bool isReverse(TreeNode* l, TreeNode* r)
{
if(!l && r) return false;
else if(l && !r) return false;
else if(!l && !r) return true;
else if(l->val != r->val) return false;
bool out = isReverse(l->left, r->right);
bool in = isReverse(l->right, r->left);
return out && in;
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;//空树
return isReverse(root->left, root->right);
}
};
迭代法 队列
class Solution {
public:
//迭代 队列
bool isSymmetric(TreeNode* root) {
if(!root) return true;//空树
queue<TreeNode*> que;
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 && !rightNode) continue;//左右节点都为空
else if(!leftNode || !rightNode) return false;//左非空,右为空
else if(leftNode->val != rightNode->val) return false;//左为空 右非空
//左右相等 更新左右的孩子 先外侧再内侧
que.push(leftNode->left);//左的左孩子
que.push(rightNode->right);//右的右孩子
que.push(leftNode->right);//左的右孩子
que.push(rightNode->left);//右的左孩子
}
return true;
}
};
递归法:和上面一样,四种情况要单独处理,然后再递归,递归的传入的是两个树的对应位置的节点
class Solution {
public:
//递归法
bool isSameTree(TreeNode* p, TreeNode* q) {
//首先要剔除情况
if(p==nullptr && q==nullptr) return true;
else if(p==nullptr || q==nullptr) return false;
else if(p->val != q->val) return false;
//节点非空 开始递归 左右节点比较
bool leftside = isSameTree(p->left, q->left);
bool rightside = isSameTree(p->right, q->right);
return leftside && rightside;
}
};
三种情况,这两个树相等、subroot是root的左子树、subroot是root的右子树
判断树相等可以用相同的树-题100来判断,然后传入根树、根的左子树、根的右子树与子树比较
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==nullptr && q==nullptr) return true;
else if(p==nullptr || q==nullptr) return false;
else if(p->val != q->val) return false;
//节点非空 开始递归 左右节点比较
bool leftside = isSameTree(p->left, q->left);
bool rightside = isSameTree(p->right, q->right);
return leftside && rightside;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
//递归结束条件
if(root==nullptr) return false;
//两个树相等 这个树是左树的子树 这个树是右树的子树
bool lefttree = isSubtree(root->left, subRoot);
bool righttree = isSubtree(root->right, subRoot);
bool sametree = isSameTree(root, subRoot);
return lefttree || righttree || sametree;
}
};
力扣二叉树专题(二)写过,不赘述
class Solution {
public:
//1.迭代法
/*int maxDepth(TreeNode* root)
{
queue que;
int depth=0;
if(root!=nullptr) que.push(root);
while(!que.empty())
{
int size = que.size();
for(int i=0;ileft) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
depth++;
}
return depth;
}*/
//2.递归法
/*
int maxDepth(TreeNode* root)
{
if(root==nullptr) return 0;
int l = maxDepth(root->left);
int r = maxDepth(root->right);
return max(l,r)+1;
}
*/
//6.递归
int depth=0;
void dfs(TreeNode* root, int level)
{
if(root==nullptr) return;
if(level>depth) depth=level;
dfs(root->left, level+1);
dfs(root->right, level+1);
}
int maxDepth(TreeNode* root)
{
if(root==nullptr) return 0;
dfs(root, 1);
return depth;
}
};
递归法,在二叉树最大深度的基础上修改了一点
class Solution {
public:
int depth = 0;
void finddepth(Node* cur, int level)
{
if(cur==NULL) return;
if(level>depth) depth = level;
for(int i=0;i<cur->children.size();i++)
{
finddepth(cur->children[i], level+1);
}
}
int maxDepth(Node* root) {
if(root==NULL) return 0;
finddepth(root, 1);
return depth;
}
};
迭代法
class Solution {
public:
int depth = 0;
int maxDepth(Node* root)
{
if(root==NULL) return 0;
queue<Node*> que;
que.push(root);
while(!que.empty())
{
int size = que.size();
for(int i=0;i<size;i++)
{
Node* cur = que.front();
que.pop();
for(int j=0;j<cur->children.size();j++)
{
if(cur->children[j]) que.push(cur->children[j]);
}
}
depth++;
}
return depth;
}
};
力扣二叉树专题(二)写过,不赘述
class Solution {
public:
//递归法
int minDepth(TreeNode* root)
{
if(root==nullptr) return 0;
int num=1;
int l=0, r=0;
if(root->left!=nullptr && root->right!=nullptr)
{
l = minDepth(root->left);
r = minDepth(root->right);
num += min(l, r);
}
else if(root->left!=nullptr && root->right==nullptr) num += minDepth(root->left);
else num += minDepth(root->right);
return num;
}
//迭代法
/*int minDepth(TreeNode* root)
{
queue que;
if(root==nullptr) return 0;
int depth = 0;
que.push(root);
while(!que.empty())
{
int size = que.size();
depth++;
for(int i=0;ileft) que.push(cur->left);
if(cur->right) que.push(cur->right);
if(cur->left==nullptr && cur->right==nullptr) return depth;//遍历到最低点
}
}
return depth;
}*/
};
迭代法 层序遍历节点
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==nullptr) return 0;
queue<TreeNode*> que;
que.push(root);
int num = 0;
while(!que.empty())
{
int size = que.size();
for(int i=0;i<size;i++)
{
TreeNode* cur=que.front();
que.pop();
num++;
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return num;
}
};
递归法 统计左右子树的节点
class Solution {
public:
int countNodes(TreeNode* root)
{
if(root==nullptr) return 0;
int left = countNodes(root->left);
int right = countNodes(root->right);
return left+right+1;
}
};
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数,可以从上往下。
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数,只能从下往上。
leetcode的题目中都是以节点为一度,即根节点深度是1;但维基百科上定义用边为一度,即根节点的深度是0。
节点6:深度1,高度4
节点2:深度2,高度3
节点4:深度3,高度2
节点3:深度4,高度1
高度是往上,深度是往下。所以,求树的最大深度可以前序遍历(中左右),也可以后序遍历,后序遍历求的是根节点的高度,即树的最大深度;求树的最大高度只能后序遍历(左右中)。
class Solution {
public:
int maxheight(TreeNode* cur)
{
if(cur==nullptr) return 0;
int left = maxheight(cur->left);
if(left==-1) return -1;
int right = maxheight(cur->right);
if(right==-1) return -1;
if(max(left, right) - min(left, right) > 1) return -1;
return max(left, right)+1;
}
bool isBalanced(TreeNode* root) {
bool result = maxheight(root);
return maxheight(root) == -1 ? false : true;
}
};
class Solution {
public:
//递归 回溯
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result)
{
path.push_back(cur->val);//中 最后一个节点也需要加入path中
//停止逻辑 在这里也拼接路径
//找到叶子节点,就开始结束的处理逻辑,把路径放进result里;当cur不为空,其左右孩子都为空的时候,就找到叶子节点
if(cur->left==nullptr && cur->right==nullptr)
{
string spath;
//将path里记录的路径转为string格式
for(int i=0;i<path.size()-1;i++)
{
spath += to_string(path[i]);
spath += "->";
}
spath += to_string(path[path.size()-1]);//记录最后一个节点(叶子节点)
result.push_back(spath);//收集一个路径
return;
}
//递归 回溯
if(cur->left)
{
traversal(cur->left, path, result);//左
path.pop_back();
}
if(cur->right)
{
traversal(cur->right, path, result);//右
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;//存放路径节点
vector<string> result;
if(root==nullptr) return result;
traversal(root, path, result);
return result;
}
};
对称二叉树,比较根节点的左右子树
二叉树最小深度,是从根节点到最近叶子节点的最短路径上的节点数量
求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数,往下,前序遍历,也可以后序遍历
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数,往上,后序遍历
leetcode中强调的深度和高度是按照节点来计算的
回溯与递归