对称二叉树
-
这道题目的本质是要比较两个树(这两个树是根节点的左右子树),遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
-
而本题的迭代法中我们使用了队列,需要注意的是这不是层序遍历,而且仅仅通过一个容器来成对的存放我们要比较的元素,认识到这一点之后就发现:用队列,用栈,甚至用数组,都是可以的。
-
递归法:
bool compare(TreeNode* left, TreeNode* right){
// 情况1:叶子节点
if(!left && !right) return true;
// 情况2:左右节点值相等,继续向下比较(递归)
else if(left && right && left->val==right->val)
return compare(left->left, right->right)
&& compare(left->right, right->left);
else return false;
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return compare(root->left, root->right);
}
- 迭代法:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
stack<TreeNode*> q; //这里使用栈或队列都可以
q.push(root->left);
q.push(root->right);
while(!q.empty()){
TreeNode* left=q.top(); q.pop();
TreeNode* right=q.top(); q.pop();
// 左节点为空、右节点为空,此时说明是对称的
if(!left && !right) continue;
// 左右一个节点不为空,或者都不为空但数值不相同,返回false
if ((!left || !right || (left->val!=right->val)))
return false;
// 注意成对放入栈(队列)中
q.push(left->left);
q.push(right->right);
q.push(left->right);
q.push(right->left);
}
return true;
}
- 相关题目:
- 100.相同的树
bool compare(TreeNode* left, TreeNode* right){
// 情况1:叶子节点
if(!left && !right) return true;
// 情况2:左右节点值相等,继续向下比较(递归)
else if(left && right && left->val==right->val)
return compare(left->left, right->left)
&& compare(left->right, right->right);
else return false;
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return compare(p,q);
}
- 572.另一个树的子树
- “递归套递归”
bool isSameTree(TreeNode* p, TreeNode* q) {
if (!p && !q) return true;
if (p && q && p->val == q->val)
return isSameTree(p->left, q->left)
&& isSameTree(p->right, q->right);
else return false;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(!root) return false;
if(isSameTree(root, subRoot)) return true;
return isSubtree(root->left, subRoot)
|| isSubtree(root->right, subRoot);
}
二叉树的最大深度
- 力扣题目链接
- 曾经学过的层序遍历法:
int maxDepth(TreeNode* root) {
queue<TreeNode*> q;
int dep=0;
if(root) q.push(root);
while(!q.empty()){
dep++;
int size=q.size();
for(int i=0; i<size; i++){
TreeNode* node=q.front();
q.pop();
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return dep;
}
- 递归法:
int maxDepth(TreeNode* root) {
if(!root) return 0;
return 1+max(maxDepth(root->left), maxDepth(root->right));
}
- 相关题目:559. n叉树的最大深度
int maxDepth(Node* root) {
if(!root) return 0;
int depth=0;
for(auto node : root->children)
depth=max(depth, maxDepth(node));
return depth+1;
}
二叉树的最小深度
- 力扣题目链接
- 最小深度是从根节点到最近叶子节点的最短路径上的节点数量
- 层序遍历法:
int minDepth(TreeNode* root) {
queue<TreeNode*> q;
int dep=0;
if(root) q.push(root);
while(!q.empty()){
dep++;
int size=q.size();
for(int i=0; i<size; i++){
TreeNode* node=q.front();
q.pop();
// 如遇到第一个叶子节点,所在层即为最小深度
if(!node->left && !node->right) return dep;
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return dep;
}
- 递归法:
int getDepth(TreeNode* root){
if(!root) return 0;
int leftDepth=getDepth(root->left);
int rightDepth=getDepth(root->right);
// 注意仔细分类!
if(!root->left && root->right) return 1+rightDepth;
else if(root->left && !root->right) return 1+leftDepth;
else return 1+min(leftDepth, rightDepth);
}
int minDepth(TreeNode* root) {
return getDepth(root);
}
完全二叉树的节点个数
- 力扣题目链接
- 充分利用完全二叉树性质!
int countNodes(TreeNode* root) {
if(!root) return 0;
TreeNode* left=root->left;
TreeNode* right=root->right;
int leftDepth=0, rightDepth=0;
while(left){
left=left->left;
leftDepth++;
}
while(right){
right=right->right;
rightDepth++;
}
// 注意(2<<1) 相当于2^2,所以leftDepth初始为0
if(leftDepth==rightDepth) return (2<<leftDepth)-1;
return countNodes(root->left)+countNodes(root->right)+1;
}
- 时间复杂度:O(log n × log n)
- 空间复杂度:O(log n)
平衡二叉树
- 力扣题目链接
- 通过本题可以了解求二叉树深度和二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历
- 前序和后序遍历本质:前序遍历意思是先访问根结点,再访问左右孩子,是一种自顶向下的处理方式;而后序遍历是先处理左右孩子,再一步一步把信息传递到根结点,是一种自底向上的方式!
int getHeight(TreeNode* root){
if(!root) return 0;
int leftHeight=getHeight(root->left);
if(leftHeight==-1) return -1;
int rightHeight=getHeight(root->right);
if(rightHeight==-1) return -1;
return abs(leftHeight-rightHeight)>1
? -1 : (1+max(leftHeight, rightHeight));
}
bool isBalanced(TreeNode* root) {
return getHeight(root)==-1 ? false : true;
}
二叉树的所有路径
- 力扣题目链接
- 回溯和递归是一一对应的,有一个递归,就要有一个回溯
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result){
path.push_back(cur->val);
if(!cur->left && !cur->right){
string s;
for(int i=0; i<path.size()-1; i++){
s+=to_string(path[i]);
s+="->";
}
s+=to_string(path[path.size()-1]);
result.push_back(s);
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) return result;
traversal(root, path, result);
return result;
}
- 精简代码:
void traversal(TreeNode* cur, string path, vector<string>& result){
// 注意path参数类型变为string
path+=to_string(cur->val); // 中
if (!cur->left && !cur->right) {
result.push_back(path);
return;
}
// 体会path隐含的回溯
if (cur->left)
traversal(cur->left, path+"->", result); // 左
if (cur->right)
traversal(cur->right, path+"->", result); // 右
}
vector<string> binaryTreePaths(TreeNode* root) {
string path;
vector<string> result;
if(!root) return result;
traversal(root, path, result);
return result;
}
参考资料
[1] 代码随想录
[2] Leetcode题解