二叉树的层平均值
“心里的期待,总是填不满。 ”
——孙燕姿
一般题解都会给深度优先搜索和广度优先搜索,两种解法。贪多嚼不烂,并且二叉树的算法题我总是感觉代码好像就是简单递归一下就算出答案了,自己写代码就是无从下手。有点难受。所以还是把深度优先搜索先拿下来。
#include<iostream>
using namespace std;
const int N = 10;
int n, path[N];
bool st[N];
void dfs( int u ) {
if ( u == n ) {
for ( int i = 0; i < n; i++ ) {
cout << path[i] << " ";
}
cout << endl;
return;
}
for ( int i = 1; i <= n; i++ ) {
if ( !st[i] ) {
path[ u ] = i;
st[ i ] = true;
dfs( u + 1 );
path[ u ] = 0;
st[ i ] = false;
}
}
}
int main() {
cin >> n;
dfs( 0 );
return 0;
}
把代码风格优化了一下,好看了不少。是不是厉害的程序员写代码都是比较优雅的,我离变成优秀的程序员更近了一步。上面这个是深度优先搜索的一个非常经典的题。今天和一个同学交流专业课的问题,我意识到一个问题,我思考问题不能停留在问题的表面,高中的时候某个大佬学长就和我说过,实际上不存在刷完 xx 题就能考多少分这种说法,关键得看自己对写过的题的消化吸收的程度,能否从第一步独立推导到最后一步,专业课的题和算法题,我感觉自己都是这个问题,就是好像能理解,但是独立写的时候还是差点意思,我可能要多写旧题。把旧题多写几遍。题解里面还有时间复杂度的分析,我现在主要是需要学习写代码,时间复杂度虽然是必须要分析的,但是要是我写不出代码,时间复杂度会分析也没用。先把这个部分砍掉。先学会怎么写代码。
针对这个具体的题,深搜的思路非常直观,就是维护每一层的节点个数和每一层的节点的和,求平均值就把两个元素做一个除法。我的问题是,怎么判断是在同一层?深度或者高度相等,还是怎么写,感觉也不是自己的问题,要是直接就会写就是发明创造了。我要对自己包容一些。要做的就是以后遇到学过的非常类似的问题能迅速解决。其他的都预设自己是解决不了的,原谅自己。力扣判题好慢啊。
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {//输入只有一个根节点
auto counts = vector< int > ();//定义一个记录节点个数的数组
auto sums = vector< double > ();//定义一个节点和的数组,数组下标是层数
dfs( root, 0, counts, sums );//层序遍历
//从根节点开始,根节点是第零层,最后两个变量是数组
auto averages = vector< double > ();//定义每层的平均值
int size = sums.size();//总的层数
for ( int i = 0; i < size; i++ ) {//把每层的平均值算出来
averages.push_back( sums[i] / counts[i] );
}//存到向量里面,向量这里定义为了 double 类型
return averages;//此题实际上就是求每层的平均值
}
void dfs( TreeNode* root, int level, vector< int > &counts, vector< double > &sums) {//深搜的变量有四个
if ( root == nullptr ) {//访问到空节点就交还权限给上级操作系统
return;//非常常见的递归的操作,就是表示递归基
}
if ( level < sums.size() ) {// level 表示层,sums.size() 表示总层数
sums[ level ] += root -> val;//更新节点和
counts[ level ] += 1;//更新节点数
//假设是 level 层,或者直观一些,直接就是 2 层,表示当前是第 2 层,
//第 2 层实际上表示的好像是第三层,看具体定义了。现在的总层数,是多少。
//总层数最开始是 0 ,也就是说最开始是进不了这个循环的。
//这里为什么是这样更新的呢。
//实际上,除了第一个点,都是更新后面的了。
// sums.size() 表示的至少是 1 ,因为根节点要首先加进去的
// 层数到后面一定是 大于等于 当前节点的和的个数。比如说算了
//前面三层,那么和数组里面只有三个数字,现在算第四层,那就进不来这个判断
//进下面的判断,然后再进现在这个判断。。我懂了。记住这种解法比较好
} else {
sums.push_back( 1.0 * root -> val );//把当前层的每个节点加到和数组
counts.push_back( 1 );//哦,算是第一个点。上面的判断是累加,这里两行
//都是表示该层的第一个节点。
}
dfs( root -> left, level + 1, counts, sums );//递归到左孩子
dfs( root -> right, level + 1, counts, sums );//递归到右孩子
}
};
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
auto sums = vector< double > ();
auto counts = vector< int > ();
dfs( root, 0, sums, counts );
int n = sums.size();
auto averages = vector< double > ();
for ( int i = 0; i < n; i++ ) {
averages.push_back( sums[ i ] / counts[ i ] );
}
return averages;
}
void dfs( TreeNode* root, int level, vector< double > &sums, vector< int > &counts ) {
if ( root == nullptr ) {
return;
}
if ( level < sums.size() ) {
sums[ level ] += root -> val;
counts[ level ] += 1;
} else {
sums.push_back( 1.0 * root -> val );
counts.push_back( 1 );
}
dfs( root -> left, level + 1, sums, counts );
dfs( root -> right, level + 1, sums, counts );
}
};
/**
* 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:
vector<double> averageOfLevels(TreeNode* root) {
auto sums = vector< double > ();
auto counts = vector< int > ();
auto averages = vector< double > ();
dfs( root, 0, sums, counts );
int n = sums.size();
for ( int i = 0; i < n; i++ ) {
averages.push_back( sums[i] / counts[i] );
}
return averages;
}
void dfs( TreeNode* root, int level, vector< double > &sums, vector< int > &counts ) {
if ( root == nullptr ) {
return ;
}
if ( level < sums.size() ) {
sums[ level ] += root -> val;
counts[ level ] += 1;
} else {
sums.push_back( 1.0 * root -> val );
counts.push_back( 1 );
}
dfs( root -> left, level + 1, sums, counts );
dfs( root -> right, level + 1, sums, counts );
}
};
我感觉这个题能写出来,真的非常不错了。虽然标签是简单题。思路确实是比较简单的,但是在树上面进行一些操作,感觉就是稍微有点难度。关键在于每次做一点点。嘿嘿。