二叉樹的基本知識
連結:https://programmercarl.com/二叉樹理論基礎.html
要點:
- 深度優先遍歷
- 前序遍歷(遞迴法,迭代法)
- 中序遍歷(遞迴法,迭代法)
- 後序遍歷(遞迴法,迭代法)
- 廣度優先遍歷
- 層次遍歷(迭代法)
由於棧就是遞迴的一種實現結構,因此前中後序遍歷的邏輯可以藉助棧使用遞迴的方式來實現。
由於佇列先進先出的特點,廣度優先遍歷一般使用佇列來實現。
遞迴的思想:
每次寫遞迴,要按照三要素去寫:
- 確定遞迴函式的引數和返回值。
- 確定終止條件。
- 確定單層遞迴的邏輯。
下面開始具體的完成演算法題目。
144. 二叉樹的前序遍歷
題目連結:https://leetcode.cn/problems/binary-tree-preorder-traversal/
題目難度:簡單
文章講解:https://programmercarl.com/二叉樹的遞迴遍歷.html
影片講解:https://www.bilibili.com/video/BV1Wh411S7xt
題目狀態:透過
遞迴思路:
使用遞迴的三要素完成遞迴操作,透過程式碼就可以看明白。
程式碼實現:
/**
* 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 traversal(TreeNode *root, vector<int> &res) {
if(root == nullptr) return;
res.push_back(root->val);
traversal(root->left, res);
traversal(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
棧的思路:
先將根結點放入棧中,然後將右孩子加入棧,再加入左孩子。
為什麼要先加入右孩子,在加入左孩子呢?因為這樣出棧的時候才是中左右的順序(可以看上圖理解)。
程式碼實現:
/**
* 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<int> preorderTraversal(TreeNode* root) {
stack<TreeNode *> st;
vector<int> res;
if(root == nullptr) return res;
st.push(root);
while(!st.empty()) {
TreeNode *node = st.top();
st.pop();
res.push_back(node->val);
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
}
return res;
}
};
145. 二叉樹的後序遍歷
題目連結:https://leetcode.cn/problems/binary-tree-postorder-traversal/
遞迴思路和上面一樣,甚至程式碼都不太變,直接看程式碼:
/**
* 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 traversal(TreeNode *root, vector<int> &res) {
if(root == nullptr) return;
traversal(root->left, res);
traversal(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
棧的思想:
將前面前序遍歷的進棧順序“中->右->左”改變一下,變為“中->左->右”,此時出棧的順序就是“中->右->左”,之後在反轉一下,變為“左->右->中”即可。
程式碼實現:
/**
* 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<int> postorderTraversal(TreeNode* root) {
stack<TreeNode *> st;
vector<int> res;
if(root == nullptr) return res;
st.push(root);
while(!st.empty()) {
TreeNode *node = st.top();
st.pop();
res.push_back(node->val);
if(node->left) st.push(node->left);
if(node->right) st.push(node->right);
}
reverse(res.begin(), res.end());
return res;
}
};
94. 二叉樹的中序遍歷
題目連結:https://leetcode.cn/problems/binary-tree-inorder-traversal/
遞迴程式碼實現:
/**
* 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 traversal(TreeNode *root, vector<int> &res) {
if(root == nullptr) return;
traversal(root->left, res);
res.push_back(root->val);
traversal(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
棧的思路:
採用指標將左孩子全部壓入棧,再遍歷出來;之後採用指標將右孩子全部壓入棧,再遍歷出來。
程式碼實現:
/**
* 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<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode *> st;
TreeNode *cur = root;
while(cur != nullptr || !st.empty()) {
if(cur != nullptr) {
st.push(cur);
cur = cur->left;
} else {
cur = st.top();
st.pop();
res.push_back(cur->val);
cur = cur->right;
}
}
return res;
}
};
102. 二叉樹的層序遍歷
題目連結:https://leetcode.cn/problems/binary-tree-level-order-traversal/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
思路:
利用佇列實現層序遍歷,並透過size
來判斷該層是否已經輸出完畢,並在輸出每一層的某個元素的時候,將該元素的左右孩子壓入佇列中,直到佇列為空,整個迴圈完畢,層序遍歷結束。
程式碼實現:
/**
* 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<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> vec;
while(size--) {
TreeNode *node = que.front();
que.pop();
vec.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(vec);
}
return res;
}
};
107. 二叉樹的層次遍歷II
題目連結:https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
思路:
按102.二叉樹的層序遍歷的思路來,只是在最後反轉一下結果即可。
程式碼實現:
/**
* 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<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> vec;
while(size--) {
TreeNode *node = que.front();
que.pop();
vec.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(vec);
}
reverse(res.begin(), res.end());
return res;
}
};
199. 二叉樹的右檢視
題目連結:https://leetcode.cn/problems/binary-tree-right-side-view/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
同樣使用層序遍歷,不同的是在每層遍歷的時候,只需要把每層最後一個元素的值壓入陣列中,最後返回這個陣列。
程式碼實現:
/**
* 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<int> rightSideView(TreeNode* root) {
queue<TreeNode *> que;
vector<int> vec;
if(root != nullptr) 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) vec.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return vec;
}
};
637. 二叉樹的層平均值
題目連結:https://leetcode.cn/problems/average-of-levels-in-binary-tree/
題目難度:簡單
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
依舊是層序遍歷,在遍歷每一層時記錄該層的個數以及該層的和,最後求得平均數,返回在一個陣列中。
程式碼實現:
/**
* 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) {
vector<double> res;
queue<TreeNode *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
int len = size;
double sum = 0;
while(size--) {
TreeNode *node = que.front();
que.pop();
sum += node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(sum / len);
}
return res;
}
};
429. N 叉樹的層序遍歷
題目連結:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
加個for
迴圈,將元素的所有孩子都加入佇列中。
程式碼實現:
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
queue<Node *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
vector<int> vec;
while(size--) {
Node *node = que.front();
que.pop();
vec.push_back(node->val);
for(int i = 0; i < node->children.size(); ++i) {
if(node->children[i]) que.push(node->children[i]);
}
}
res.push_back(vec);
}
return res;
}
};
515. 在每個樹行中找最大值
題目連結:https://leetcode.cn/problems/find-largest-value-in-each-tree-row/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
加個max
,若該層有比max
大的元素,該元素的值就是max
,最後在陣列中存入該層的max
即可。
程式碼實現:
/**
* 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<int> largestValues(TreeNode* root) {
queue<TreeNode *> que;
vector<int> res;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
int max = INT_MIN;
while(size--) {
TreeNode *node = que.front();
que.pop();
max = max > node->val ? max : node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(max);
}
return res;
}
};
116. 填充每個節點的下一個右側節點指標
題目連結:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
定義一個leftmost
來儲存每層最左邊的元素,遍歷每層元素時,將leftmost
的next
指向其後面一個元素,並更新leftmost
為當前元素,直到該層遍歷完。
程式碼實現:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue<Node *> que;
Node *leftmost;
if(root != nullptr) {
que.push(root);
leftmost = root;
}
while(!que.empty()) {
int size = que.size();
for(int i = 0; i < size; ++i) {
Node *node = que.front();
que.pop();
if(i > 0) {
leftmost->next = node;
}
leftmost = node;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return root;
}
};
117. 填充每個節點的下一個右側節點指標II
題目連結:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/
題目難度:中等
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
和上一次思路一樣,甚至實現程式碼都一樣。
程式碼實現:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue<Node *> que;
Node *leftmost;
if(root != nullptr) {
que.push(root);
leftmost = root;
}
while(!que.empty()) {
int size = que.size();
for(int i = 0; i < size; ++i) {
Node *node = que.front();
que.pop();
if(i > 0) {
leftmost->next = node;
}
leftmost = node;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return root;
}
};
104. 二叉樹的最大深度
題目連結:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
題目難度:簡單
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
個人思路:
層序遍歷,記錄有幾層,層數就是二叉樹的最大深度。
程式碼實現:
/**
* 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) {
int high = 0;
queue<TreeNode *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
high++;
while(size--) {
TreeNode *node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return high;
}
};
111. 二叉樹的最小深度
題目連結:https://leetcode.cn/problems/minimum-depth-of-binary-tree/
題目難度:簡單
文章講解:https://programmercarl.com/0102.二叉樹的層序遍歷.html
影片講解:https://www.bilibili.com/video/BV1GY4y1u7b2
題目狀態:透過
思路:
當一個節點既沒有左孩子也沒有右孩子時,這個節點就是葉子節點,而根結點到葉子節點中間的節點數就是兩者之間的高度。
程式碼實現:
/**
* 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) {
int high = 0;
queue<TreeNode *> que;
if(root != nullptr) que.push(root);
while(!que.empty()) {
int size = que.size();
high++;
while(size--) {
TreeNode *node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
if(!node->left && !node->right) return high;
}
}
return high;
}
};