一、前言
参考文献:代码随想录
今天的题目比较多,但是应该都不会很难,我记得在我寒假刷的时候,刷了很久二叉树,发现有一段时间的i题目类型很类似(我大概一天一到两题),所以耽搁了比较久的时间,这次跟着代码随想录训练营,应该可以很快把二叉树给过掉。
二、层序遍历
1、思路:
层序遍历的模板都差不多,我总结了以下几点:
(1)层序遍历就好比广度搜索,利用的是队列的性质(先进先出)
(2)首先创建一个queue(队列)来存储遍历的值,首先存入的是root
(3)进入大循环,再把当前节点的值存入result中。
(4)把左右孩子放入队列中(至于是先放右孩子还是左孩子,取决于题目要求)
2、二叉树的层序遍历代码:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if (root == NULL) return result;
que.push(root);
while (!que.empty())
{
int size = que.size();
vector<int> temp;
for (int i = 0; i < size; i++)
{
TreeNode* node = que.front();
que.pop();
temp.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
// 把temp存到result中
result.push_back(temp);
}
return result;
}
3、二叉树的层序遍历 II代码:
这个题目就是从叶子节点开始遍历,与从根节点对比来说,只需要反转一下即可
代码如下:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if (root == NULL) return result;
que.push(root);
while (!que.empty()) {
int size = que.size();
vector<int> temp;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
temp.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(temp);
}
reverse(result.begin(), result.end());
return result;
}
4、二叉树的右视图代码:
右视图的解法与其类似,只需要把树每一层最后一个节点存起来就ok了
代码如下:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if (root == NULL) return result;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
// 最后一个元素才添加
if (i == size - 1) {
result.push_back(node->val);
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
5、二叉树的层平均值代码:
这也是考察层序遍历,主要还是运用当前的框架,利用queue来实现每一层的遍历,求和以及求平均,代码如下:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> que;
vector<double> result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()) {
int size = que.size();
double sum = 0;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
sum += node->val;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
// 传入平均值
result.push_back(sum / size);
}
return result;
}
6、N 叉树的层序遍历代码:
这个N叉树的遍历还是使用queue来左层序遍历,这里只是多了几个孩子节点。(我主要是不知道孩子节点应该如何去遍历) 查看了代码随想录之后,就明白了,孩子节点的遍历与数组差不多。
代码如下:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
queue<Node*> que;
if (root == NULL) return result;
que.push(root);
while (!que.empty()) {
int size = que.size();
vector<int> temp;
for (int i = 0; i < size; i++) {
Node* node = que.front();
que.pop();
temp.push_back(node->val);
// 插入树的孩子节点
for (int j = 0; j < node->children.size(); j++) {
que.push(node->children[j]);
}
}
result.push_back(temp);
}
return result;
}
7、在每个树行中找最大值代码:
这个题目也大差不差,主要差别就是多了一个判断大小的流程,其余都差不多。
代码如下:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if (root == NULL) return result;
que.push(root);
while(!que.empty()) {
int size = que.size();
int max = INT_MIN;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->val > max) {
max = node->val;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(max);
}
return result;
}
8、填充右节点代码:
其实都是大差不差,但是这里的关键就是需要设置两个指针,一个指针保存前一个节点,让这个节点能够指向后一个节点,再把最后的节点指向NULL就ok了。
代码如下:
Node* connect(Node* root) {
queue<Node*> que;
if (root == NULL) return root;
que.push(root);
while (!que.empty()) {
Node* nodeper; // 前一个节点
Node* node;
int size = que.size();
for (int i = 0; i < size; i++) {
if (i == 0) {
nodeper = que.front();
node = nodeper; // 这里必须设置,因为为头结点时,就需要通过这个节点访问
que.pop();
} else {
node = que.front();
que.pop();
nodeper->next = node;
nodeper = node;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodeper->next = NULL; // 最后一个元素指向空
}
return root;
}
9、填充右节点||代码:
这道题目与上一个题目相同,就是一模一样的题目,代码也一模一样,我就不列出来了。
10、二叉树的最大深度代码:
这道题目只要直接往下遍历,遍历一层,就统计加一就ok了。
代码如下:
int maxDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> que;
if (root == NULL) return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return depth;
}
11、二叉树的最小深度代码:
与最大深度相比,多了一个出去的条件,两个左右孩子节点都为空时,就return
int minDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> que;
if (root == NULL) return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if (node->left == NULL && node->right == NULL) { // 左右孩子都为空了,就说明到了最底层了,返回即可
return depth;
}
}
}
return depth;
}
12、反转二叉树代码:
这个题目用的是递归的方法,比较抽象,所以我先使用的是迭代法。
我总结了以下几点
(1)可以使用栈或者队列,我这里使用的是队列。
(2)只需要按照之前的模板,但是不需要再遍历每一层的了,只需要交换,每一个左右节点就可以了。
(3)这里使用的是后序遍历。
代码如下:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
// 交换左右子节点
TreeNode* temp = node->left;
node->left = node->right;
node->right = temp;
}
return root;
}
递归法:
递归首先就是要确定:
(1)返回值和传入参数。
(2)终止条件
(3)处理过程
这里传入的参数是root指针,返回值是Treenode*类型的,终止条件就是root不额为空即可,中间过程看下列代码即可:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return NULL;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
这里使用的是前序遍历,中序遍历不行,因为会反转两次,所以后序遍历也可以。
13、对称二叉树代码:
这个题目就是用递归解决的,这里需要确定终止条件(条件比较多),还有采用的比较抽象的遍历方式。
这里传入的参数是左子树和右子树,他需要分别比较内的和外侧,即:
right->right : left->left;
left->right : right->left;
这两进行比较
主要思路就是外侧和外侧的比较,内测和内侧的比较,比较完了就OK了。
代码如下:
private:
bool comper(TreeNode* left,TreeNode* right) {
if (left != NULL && right == NULL) return false;
else if (right != NULL && left == NULL) return false;
else if (right == NULL && left ==NULL) return true;
// 值不相等
else if (left->val != right->val) return false;
// 开始内部实现,后序遍历
return comper(left->left, right->right) && comper(right->left, left->right);
}
public:
bool isSymmetric(TreeNode* root) {
return comper(root->left, root->right);
}
这里的终止条件就是比较复杂:
(1)做指针为空,右指针不为空,返回 否
(2)左指针不为空,右指针为空, 返回 否
(3) 做指针为空, 右指针为空, 返回 真
(4)左指针和右指针的数值不相等, 返回 否
(5) 左指针和右指针数值相同,就继续往下去递归,判断左右节点的孩子节点是否对称。
今天的学习时间安慰两小时;
Leave a message:
How can a world be good in which money is the moving power,and self-interest the guiding star?