38、对称二叉树
题目简介:
给你一个二叉树的根节点 root
, 检查它是否轴对称。
初见思路:
感觉没什么思路,是不是得用特定的遍历顺序呢?前、中、后序的特性,我的第一反应应该是。
算法思路:
太妙了,实在是太妙了,后序遍历的魅力
所谓后续遍历,就是要收集下方所有子树的信息之后,再进行处理根节点,只要符合这个思路的问题,应该都要这样做。
还是三部曲:
1、先确定返回值与形参:
这里我就没想到了,我还想着的是一个节点一个节点处理,然后写的时候就发现根本不知道另一半子树的任何信息,所以失败了。应该将根节点的左、右子树都拿过来,然后再进行比较。
2、确定终止条件:
这里又没想到了,主要就是我把所有的情况都写出来了,左右都为空、左右一个不为空、左右都不为空然后判断是否值相等,值不等肯定就不能反转了,但是主要的,我以为值相等就会return true;
了,然后我就发现不对了,左右相等就return
吗?那不是完全不知道下面的树的情况了?
所以,这里也是精髓,原来,如果左右值相等我们才进入下面的判断,也就是所谓的外侧与内侧判断。
3、单层处理逻辑:
这里就更是妙中之妙,玄之又玄!
外侧结果,就是传入左子树的左边和右子树的右边!
内侧结果,就是传入左子树的右边和右子树的左边!
太妙了实在是,我一开始还完全不理解,我不是一直在半边进行判断吗?怎么知道另外半边的情况,这里由步骤2
给出了解答。我还不知道怎么处理外侧和内侧,这里3
给出了解答,我只能说卡哥牛逼!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool traversal(TreeNode* left,TreeNode* right){
if(left == nullptr && right == nullptr) return true;
else if(left != nullptr&& right == nullptr) return false;
else if(left == nullptr && right != nullptr) return false;
else if(left != nullptr && right != nullptr){
if(left->val != right->val) return false;
}
auto outresult = traversal(left->left,right->right);
auto insresult = traversal(left->right,right->left);
return outresult && insresult;
}
bool isSymmetric(TreeNode* root) {
return traversal(root->left,root->right);
}
};
39、二叉树最大深度
题目简介:
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
初见思路:
well
,这道题就是层序遍历的经典题了,一层层的往下走,然后到了新的一层就可维护一个层高,然后层序遍历完之后就能找到depth
了。
经典的框架,这是第十一边写了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;
if(root != nullptr) que.push(root);
int depth =0;
while(!que.empty()){
size_t size = que.size();
depth++;
while(size--){
auto cur = que.front();
que.pop();
if(cur != nullptr){
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
}
return depth;
}
};
40、二叉树最小深度
题目简介:
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
**说明:**叶子节点是指没有子节点的节点。
初见思路:
因为层序是从上往下走的,所以只要触发了停止条件就能保证,当前是最小的深度,而且每一层的元素是遍历的,所以不会有错漏的地方。
现在再来谈一谈停止的条件,什么时候我们会说不会有下一层了,那就是一个节点的左、右子树都是nullptr的时候,那么就不会有下一层,他就是一个叶节点了。
那么现在我们只要判断,哪一层的哪一个节点只要是叶节点了,那么这就是最小深度了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*> que;
if(root != nullptr) que.push(root);
int depth = 0;
while(!que.empty()){
size_t size = que.size();
depth++;
while(size--){
auto cur = que.front();
que.pop();
if(cur != nullptr){
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
if( cur->left == nullptr && cur->right == nullptr )
return depth;
}
}
}
return depth;
}
};
二叉树的种类
1、满二叉树
他的节点数量等于2^k-1
,其中k
是深度。
2、完全二叉树
除了底层,其他的节点都是满的,且底层从左到右都是连续的。
3、二叉搜索树
左子树都小于根节点,右子树都大于根节点。对于节点的结构没有太大的约束。
4、平衡二叉搜索树
左子树和右子树的高度不能超过1;
可以看见,左子树是一个平衡二叉搜索树,左右子树之间也只相差1的高度,所以这是一个平衡二叉搜索树。
41、完全二叉树的节点数量
题目简介:
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层(从第 0 层开始),则该层包含 1~ 2h
个节点
初见思路:
虽然我很想直接就层序遍历秒掉它,但是我觉得还是得听一听思路,因为这题明确了是一个完全二叉树,那一定就要用到完全二叉树的特点才行。
那完全二叉树的特点有哪些呢?
第一,除了底部可能是不满的,其他的节点都是满的。
第二,底部从左到右是连续的。
那么,我是不是只要知道底部的深度,然后知道底部从左到右有几个节点就ok
了?那感觉还不如直接数就好了?
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int traversal(TreeNode* cur){
if(cur == nullptr) return 0;
int left = traversal(cur->left);
int right = traversal(cur->right);
return left+right +1;
}
int countNodes(TreeNode* root) {
return traversal(root);
}
};
这就是遍历了所有的节点才行的方法。
算法思路:
我的感觉就是算法思路就是做了一个剪枝,都新增了一个终止条件,也就是如果是满二叉树就直接返回一个2 * k - 1
的个数。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int traversal(TreeNode* cur){
if(cur == nullptr) return 0;
else{
TreeNode* leftnode = cur->left;
TreeNode* rightnode = cur->right;
int leftdepth =0;
int rightdepth = 0;
while(leftnode){
leftnode = leftnode->left;
leftdepth++;
}
while(rightnode){
rightnode = rightnode->right;
rightdepth++;
}
if(leftdepth == rightdepth) return (2 << leftdepth )-1;
}
int left = traversal(cur->left);
int right = traversal(cur->right);
return left+right +1;
}
int countNodes(TreeNode* root) {
return traversal(root);
}
};
利用了完全二叉树的特点,对于一个完全二叉树,你大概率能找到一个满二叉树。然后直接剪枝计算不用递归了。
42、平衡二叉树
题目简介:
给定一个二叉树,判断它是否是 平衡二叉树
初见思路:
遍历左右的子树的高度,然后看看是不是每一个子树的左右子树高度差为1吗?
注意,这里用的是高度,也就是而不是深度,所以,一个树的高度,等于他的最大深度。
哎呀我咋写不出来呀,我能算出每个子树的高度,这没错,但是判断他是不是平衡二叉树的地方应该在什么地方呢?
算法思路:
我无语了,算法思路中,直接用-1这个值代表了不是平衡二叉树的信号,也就解答了我在什么地方进行判断的答案。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
int traversal(TreeNode* cur) {
if (cur == nullptr)
return 0;
int left = traversal(cur->left);
int right = traversal(cur->right);
if(left == -1 || right == -1) return -1;
if((left-right) *(left-right) >1) return -1;
else return max(left, right) + 1;
}
bool isBalanced(TreeNode* root) {
int result = traversal(root);
if(result != -1) return true;
else return false;
}
};
这道题我觉得很好的锻炼了我的递归思维,我发现了在递归时信息传递的困难和什么时候应该传递信息,我觉得还是不错的。
43、二叉树的所有路径
题目简介:
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
初见思路:
我能想到的就是定义一个二维数组,然后循环的时候每个节点再创建一个一维数组来保存节点,然后进入递归,最后把路径也存在二维数组里,然后一直把二维数组也作为形参传入递归中。
void treversal(TreeNode* cur,vector<vector<TreeNode*>> & path){
if(cur == nullptr) return;
vector<TreeNode*> sonpah;
sonpah.push_back(cur);
treversal(cur->left,sonpah);
treversal(cur->right,sonpah);
path.push_back(sonpah);
}
大概是这种思路,但是我不敢保证这个路径的正确性,我的脑子不够了。而且我还不知道怎么输出一个vector<string>
,尊武与。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void treversal(TreeNode* cur,vector<int>&path,vector<string>&result){
path.push_back(cur->val);
if(cur->left == nullptr && cur->right == nullptr){
string tem_path;
for(int i=0;i<path.size()-1;i++){
tem_path += to_string(path[i]);
tem_path += "->";
}
tem_path +=to_string(path[path.size()-1]);
result.push_back(tem_path);
return ;
}
if(cur->left){
treversal(cur->left,path,result);
path.pop_back();
}
if(cur->right){
treversal(cur->right,path,result);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
vector<int> path;
if(root==nullptr) return result;
treversal(root,path,result);
return result;
}
};
救命,感觉回溯的感觉还是有点不理解,感觉和递归好像,但有完全是两个步骤,回溯更加是对于path
来讲的,但是递归是对程序说的。