其实整个二叉树的问题都是前中后序的问题
递归法,迭代法,层序遍历,基本所有二叉树都可以用这三个方法解决
递归法往往一看就会一作就废;
层序遍历挺清晰的但是可能会超时
迭代法就是递归和层序的展开,要用栈或者队列
深度优先
递归遍历
前序遍历: 中左右
class Solution {
public:
void func(TreeNode* cur,vector<int>& vec){
if(cur==nullptr) return;
vec.push_back(cur->val);
func(cur->left,vec);
func(cur->right,vec);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
func(root,res);
return res;
}
};
中序遍历(中左右)
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
vec.push_back(cur->val); // 中
traversal(cur->right, vec); // 右
}
后序遍历(左右中)
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
vec.push_back(cur->val); // 中
}
迭代遍历
前序遍历:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
}
return result;
}
};
中序遍历:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur != NULL || !st.empty()) {
if (cur != NULL) {
st.push(cur);
cur = cur->left;
} else {
cur = st.top();
st.pop();
result.push_back(cur->val);
cur = cur->right;
}
}
return result;
}
};
后序遍历:
中右左————左中右
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left);
if (node->right) st.push(node->right);
}
reverse(result.begin(), result.end());
return result;
}
};
广度优先
层序遍历
10道层序遍历的经典题
- 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)
- 111.二叉树的最小深度
代码01 (用queue一层一层来)
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
vector<vector<int>> result;
while (!que.empty()) {
int size = que.size();
vector<int> vec;
for (int i = 0; i < size; i++) {
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);
}
result.push_back(vec);
}
return result;
}
};
代码02(用depth递归)
# 递归法
class Solution {
public:
void order(TreeNode* cur, vector<vector<int>>& result, int depth)
{
if (cur == nullptr) return;
if (result.size() == depth) result.push_back(vector<int>());
result[depth].push_back(cur->val);
order(cur->left, result, depth + 1);
order(cur->right, result, depth + 1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
int depth = 0;
order(root, result, depth);
return result;
}
};
经典题目复现
( 前面是思路,后面是代码)
1.翻转二叉树. - 力扣(LeetCode)
2.对称二叉树. - 力扣(LeetCode)
该节点左边的子树和右边的子树完全相等,就要求左子树的左边=右子树的右边;左子树的右边=右子树的左边
3.二叉树的最大深度. - 力扣(LeetCode)
层序遍历or递归,注意用递归写的时候depth一定只能定义为0,否则底层的节点深度不为1
单层递归:maxDepth=1+max(左子树深度,右子树深度)
递归终止条件:if(!root) return 0;
层序遍历就是在while循环下,for循环外面加一个depth++,while结束后返回depth
4.二叉树的最小深度. - 力扣(LeetCode)
与求最大深度又所不同:minDepth!=1+min(左子树最小深度,右子树最小深度)
单层递归:
//情况一:左子树为空,右子树不为空:return 1+右子树最小深度
//情况二:左子树不为空,右子树为空:return 1+左子树最小深度
//情况三:左右子树都不为空,这时才是:return 1+min(左子树最小深度,子树最小深度)
递归终止条件:同求最大深度
层序遍历:在while循环里面,depth++,for循环里面,如果有节点的左右子节点为空就返回此时的深度
5.完全二叉树的节点个数. - 力扣(LeetCode)
思路一:递归:单层递归逻辑:1+左子树节点个数+右子树节点个数
递归终止条件: if(!root) return 0;
思路二:层序遍历:for循环里面 添一句 result++;
6.左叶子之和. - 力扣(LeetCode)
思路一:递归:单层递归逻辑:左子树左叶子之和+右子树左叶子之和
递归终止条件:root==null return0;
有一点需要注意,因为判断某节点是不是左子叶,需要用父节点,如果某节点的左右子节点都是空,那么是不能确定这个点是不是左子叶的,所以仍然返回0,而在左节点那里做一个if判断
思路二:层序遍历:
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL)
result += node->left->val;
7.平衡二叉树. - 力扣(LeetCode)
①这道题与前面的又所不同了,涉及到了回溯
②要理解高度与深度的不同
③一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1
8.二叉树的所有路径. - 力扣(LeetCode)
二叉搜索树
9.二叉搜索树中的搜索. - 力扣(LeetCode)
就是三种情况:根结点的值=/</>val,可以用递归或者迭代【易】
10.验证二叉搜索树. - 力扣(LeetCode)
利用到了二叉搜索树的特征,左<中<右,通过中序遍历将值存放到数组,最后只需要判断数组是不是单调递增的就行
方法二:不用数组,在中序遍历过程中直接判断就好了
这里有个细节,题目中最小值到了2^-31也就是int的最小值了,所以得用LONG_MIN作为max_val
NOTE:具体见这篇博客:http://t.csdnimg.cn/3DXBR
long long maxVal = LONG_MIN;
11.二叉搜索树的最小绝对差. - 力扣(LeetCode)
12.二叉搜索树中的众数. - 力扣(LeetCode)
用map:
有一些相关知识:http://t.csdnimg.cn/pjba3
13二叉搜索树中的插入操作. - 力扣(LeetCode)
TreeNode* insertIntoBST(TreeNode* root, int val) { if (!root) { TreeNode* node = new TreeNode(val); return node;} if (val > root->val) root->right = insertIntoBST(root->right, val); if (val < root->val) root->left = insertIntoBST(root->left, val); return root; }
方二迭代:一判空,二找点,三插入
14删除二叉搜索树中的节点. - 力扣(LeetCode)
用递归判空有五种情况:
首先就是root为空,
root->val==key:二是删叶子节点,三是该点左为空有不为空,四是反过来,五是删的点左右都不为空