目录
102.二叉树的层序遍历(opens new window) - 實作
107.二叉树的层次遍历II(opens new window) - 實作
199.二叉树的右视图(opens new window) - 實作
637.二叉树的层平均值(opens new window) - 實作
429.N叉树的层序遍历(opens new window) - 實作
515.在每个树行中找最大值(opens new window) - 實作
116.填充每个节点的下一个右侧节点指针(opens new window) - 實作
117.填充每个节点的下一个右侧节点指针II(opens new window) - 實作
104.二叉树的最大深度(opens new window) - 實作
層序遍歷筆記
一層一層的遍歷二叉數,透過Queue先進先出的特性,以及紀錄目前的層數size大小,來記錄二叉樹的每層數值
整個過程就相識俄羅斯套娃的感覺,但這個不是一層套一個,而是一層可以套兩個,規則是每次只能拿走當下最大的
把大的拿走後下面有兩個中套娃,拿走其中一中個套娃發現下面還有兩個小套娃,但根據規則,要先把中的拿完,所以我們眼睛就知道目前下一層有兩個小的
再把最後一個中的拿走,發現下面有一個,所以小套娃目前總共有三個,代表下一次要拿三個
如果根據遞迴的想法,那就是
- 參數值是甚麼? root節點、result二維陣列 ( 二維陣列第一個部分是深度,第二個部分是廣度)
- 終止條件是甚麼? root == null
- 單遞迴的條件是甚麼? root→left & root right 放入queue當中。
Code
迭代寫法
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> tree_que;
if(root != NULL) tree_que.push(root);
vector<vector<int>> results;
while(!que.empty()) {
int size = tree_que.size();
vector<int> vec;
while(size--) {
TreeNode* node = tree_que.front();
tree_que.pop();
vec.push_back(node->val);
if(node->left) tree_que.push(node->left);
if(node->right) tree_que.push(node->right);
}
results.push_back(vec);
}
return result;
}
遞迴寫法
class Solution {
public:
void order(TreeNode* cur, vector<vector<int>>& results, int depth) {
if(cur == NULL) return; //終止條件
if(result.size() == depth) result.push_back(vector<int>()); // 如果,result目前的一維陣列數量 == 目前的深度 ,那加一組一維陣列,這樣才會符合樹的結構
result[depth].push_back(cur->val);
order(cur->left, results, depth + 1);
order(cur->right, results, depth + 1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> results;
int depth = 0;
order(root, results, depth);
return result;
}
102.二叉树的层序遍历(opens new window) - 實作
思路
錯誤思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是root == null || !queue.size()
- 單循環 root的下一層左右子樹加入到Queue當中
錯誤點,終止條件設錯,root並不會變化,也並不是!queue.size()
正確思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層左右子樹加入到Queue當中
Code
錯誤代碼
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(root != NULL || !que.size()) {
int size = que.size();
vector<int> tmp;
while(size--) {
TreeNode* node = que.front();
que.pop();
tmp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
result.push_back(tmp);
}
return result;
}
};
正確代碼
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> tmp;
while(size--) {
TreeNode* node = que.front();
que.pop();
tmp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
result.push_back(tmp);
}
return result;
}
};
107.二叉树的层次遍历II(opens new window) - 實作
思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層左右子樹加入到Queue當中
- 最後reverse results
Code
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> tmp;
while(size--) {
TreeNode* node = que.front();
que.pop();
tmp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
result.push_back(tmp);
}
reverse(result.begin(), result.end());
return result;
}
};
199.二叉树的右视图(opens new window) - 實作
思路
錯誤思路
- 建立
- 一個一維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層右子樹加入到Queue當中
錯誤點:假設下一層只有一個數字,並且在左節點就會沒抓到,要改為去抓最右邊的數值,也就是每一層最後一個數值
正確思路
- 建立
- 一個一維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環
- 假設遞迴到最後一個數值,加入result
- root的下一層左右子樹加入que
Code
錯誤代碼
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
while(size--) {
TreeNode* node = que.front();
que.pop();
result.push_back(node->val);
if(node->right) que.push(node->right);
}
}
return result;
}
};
正確代碼
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root != NULL) 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;
}
};
637.二叉树的层平均值(opens new window) - 實作
思路
- 建立
- 一個一維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- sum += node→val
- 假設i == size - 1 將數值平均後加入result
- 單循環 root的下一層左右子樹加入到Queue當中
Code
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
double size = que.size();
double sum = 0;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
sum += node->val;
que.pop();
if (i == (size - 1)) result.push_back(sum/size);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
429.N叉树的层序遍历(opens new window) - 實作
思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層child node加入到Queue當中
Code
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
queue<Node*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> tmp;
while(size--) {
Node* node = que.front();
que.pop();
tmp.push_back(node->val);
for(int i = 0; i < node->children.size(); i++) {
if(node->children[i]) que.push(node->children[i]);
}
}
result.push_back(tmp);
}
return result;
}
};
515.在每个树行中找最大值(opens new window) - 實作
思路
- 建立
- 一個一維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 比較大小,假設數值較大則取代為max
- 假設i == size - 1 將將最大值加入result
- 單循環 root的下一層左右子樹加入到Queue當中
Code
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root != NULL) 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();
if(node->val > max) max = node->val;
que.pop();
if (i == (size - 1)) result.push_back(max);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
116.填充每个节点的下一个右侧节点指针(opens new window) - 實作
思路
錯誤思路
- 建立
- 一個一維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環
- 回圈大小設為size +1
- 假設遞迴到最後一個數值設定為null,加入result
- root的下一層左右子樹加入que
正確思路
- 建立
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 循環
- 紀錄prenode 以及當下node
- 假設i=0 代表頭節點
- 假設不為零代表非頭節點
- 進行NODE的串接
Code
錯誤代碼
class Solution {
public:
Node* connect(Node* root) {
vector<int> result;
queue<Node*> que;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
for (int i = 0; i < size + 1; i++) {
Node* node = que.front();
que.pop();
if (i == (size)) result.push_back(NULL);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
正確代碼
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (root != NULL) que.push(root);
while (!que.empty()) {
int size = que.size();
// vector<int> vec;
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
if (i == 0) {
nodePre = que.front();
que.pop();
node = nodePre;
} else {
node = que.front();
que.pop();
nodePre->next = node;
nodePre = nodePre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL;
}
return root;
}
};
117.填充每个节点的下一个右侧节点指针II(opens new window) - 實作
思路
- 建立
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 循環
- 紀錄prenode 以及當下node
- 假設i=0 代表頭節點
- 假設不為零代表非頭節點
- 進行NODE的串接
Code
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (root != NULL) que.push(root);
while (!que.empty()) {
int size = que.size();
// vector<int> vec;
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
if (i == 0) {
nodePre = que.front();
que.pop();
node = nodePre;
} else {
node = que.front();
que.pop();
nodePre->next = node;
nodePre = nodePre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL;
}
return root;
}
};
104.二叉树的最大深度(opens new window) - 實作
思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層左右子樹加入到Queue當中
- 每次循環depth +1
- 最後reverse resul
Code
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;
int depth = 0;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
while(size--) {
TreeNode* node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
depth++;
}
return depth;
}
};
111.二叉树的最小深度 - 實作
思路
- 建立
- 一個二維矩陣進行結果儲存與回傳
- 一個Queue儲存暫存結果
- 一個size,記錄每一層的數量
- 終止條件是!queue.empty()
- 單循環 root的下一層左右子樹加入到Queue當中
- 假設某一次左右子樹都為null,則直接return ++depth
- 每次循環depth +1
Code
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*> que;
int depth = 0;
if(root != NULL) que.push(root);
while(!que.empty()) {
int size = que.size();
while(size--) {
TreeNode* node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
if(!node->right && !node->left ) return ++depth;
}
depth++;
}
return depth;
}
};
226.翻转二叉树 - 實作
思路
- 利用前序遍歷,遍歷二叉數
- 翻轉二叉樹的左右子樹。
- 將左右子樹放入stack
Code
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
stack<TreeNode*> st;
st.push(root);
while(!st.empty()) {
TreeNode* node = st.top(); // 中
st.pop();
swap(node->left, node->right);
if(node->right) st.push(node->right); // 右
if(node->left) st.push(node->left); // 左
}
return root;
}
};
101.对称二叉树 2 - 實作
思路
- 因為是要比較root下面的左右子樹是否為對稱的,所以使用遞迴需要傳入左右子樹
- 假設不對稱,返回false,假設對稱返回true
- 終止條件為node為空,假設左節點為空右節點不為空,不對稱,假設右節點為空左節點不為空,不對稱,兩者為空對稱
- 單層遞迴的概念是,外比外內筆內,所以遞迴十,左樹放左節點,右樹放右節點,反之依然,左樹放右節點,右樹放左節點
- 判斷ouside and inside 是否相等
Code
總結
自己实现过程中遇到哪些困难
今天在實現的過程中,其實對於層序遍歷以及翻轉與對稱還需要花比較多時間去理解,一方面也是題目比較多,另一方面其實是時間的緣故,時間比較趕,但還是希望今天可以先碰一些,週六週日來做整理
今日收获,记录一下自己的学习时长
今天大概學了三小時左右,學了層序遍歷,其實整體還是蠻有趣的,雖然是模板,但是在不同的狀況下都有不同的玩法,其實真的蠻有趣的
相關資料
层序遍历
题目链接/文章讲解/视频讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
226.翻转二叉树
题目链接/文章讲解/视频讲解:https://programmercarl.com/0226.翻转二叉树.html
101. 对称二叉树
题目链接/文章讲解/视频讲解:https://programmercarl.com/0101.对称二叉树.html