目录
1.简单
2.中等
2.1验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/validate-binary-search-tree
学过验证二叉搜索树的方法:中序遍历,所得到的节点数值肯定是递增的。所以设置一个last指针指向中序遍历过程中当前节点的上一个节点。
TreeNode* last = nullptr;
bool flag = false; //如果出现last->val >= t->val的情况,置true
void ldr(TreeNode *t){
if(t){
ldr(t->left);
if(last == nullptr){ //最左的一个节点
last = t;
}
if(last != t){
if(last->val >= t->val)
flag = true;
}
last = t;
ldr(t->right);
}
}
bool isValidBST(TreeNode* root) {
ldr(root);
return !flag;
}
2.2二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
中序遍历的递归方法很简单了
void ldr(vector<int> &res, TreeNode* p){
if(p){
ldr(res, p->left);
res.push_back(p->val);
ldr(res, p->right);
}
}
迭代算法很容易想到用栈,但是结束条件是什么呢?因为栈在迭代过程中会出现为空的情况。 根据观察可以发现,当迭代到最右端的节点(如果它有左节点,应该是已经遍历到了),它的右节点为空,此时栈也为空,所以为结束条件。
void fun(vector<int> &res, TreeNode* t){
stack<TreeNode*> stack1;
while (t != nullptr || !stack1.empty()){
while(t){ //先依次把左节点加入到栈
stack1.push(t);
t = t->left;
}
t = stack1.top(); //提出栈顶元素
res.push_back(t->val);
stack1.pop();
t = t->right; //t可能为空或指向右节点
}
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
fun(res, root);
return res;
}
2.3二叉树的层次遍历
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
int count = 0; // 每层节点计数
int flag = 1; // 记录下一层结束的位置
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root == nullptr)
return res;
queue<TreeNode*> que;
vector<int> temp;
que.push(root);
while (!que.empty()){
TreeNode* t = que.front();
temp.push_back(t->val);
count++;
if(t->left) que.push(t->left);
if(t->right) que.push(t->right);
que.pop();
//一层结束
if(count == flag){
res.push_back(temp);
temp.clear();
flag = que.size();
count = 0;
}
}
return res;
}
2.4二叉树的锯齿形层次遍历
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal
使用双向队列(C++中为deque),每层分为前取后放(一般的队列)和前放后取两种情况,交替进行。
int count = 0;
int flag = 1;
int zigzagFlag = 0;
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root == nullptr)
return res;
deque<TreeNode*> que;
vector<int> temp;
que.push_back(root);
while (!que.empty()){
if(zigzagFlag == 0){ //前取后放
TreeNode* t = que.front();
temp.push_back(t->val);
que.pop_front();
if(t->left) que.push_back(t->left);
if(t->right) que.push_back(t->right);
} else{ //后取前放
TreeNode* t = que.back();
temp.push_back(t->val);
que.pop_back();
if(t->right) que.push_front(t->right);
if(t->left) que.push_front(t->left);
}
count++;
//一层
if(count == flag){
res.push_back(temp);
temp.clear();
flag = que.size();
count = 0;
if(zigzagFlag == 0)
zigzagFlag = 1;
else
zigzagFlag = 0;
}
}
return res;
}
2.5不同的二叉搜索树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees
不看参考是真的想不出来,卡特兰数,tql。
int numTrees(int n) {
vector<int> dp(n + 1);
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i < n + 1; ++i) {
for (int j = 1; j < i + 1; ++j) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
3.困难
3.1恢复二叉搜索树
二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/recover-binary-search-tree
这道题我的做法跟验证二叉搜索树一样,递归的中序遍历,如例子中,遍历的顺序是【3,2,1】,3>2显然不是二叉搜索树,但具体是跟哪个节点交换,还要记录当前值,继续递归,直到遍历到1节点,即检测到非二叉搜索树后中序遍历,最小的那个节点。将3和1交换。
TreeNode *last = nullptr, *x = nullptr, *y = nullptr;
int flag = 0;
void ldr(TreeNode* t){
if(t){
ldr(t->left);
if(last == nullptr){
last = t;
} else{
if(flag == 0){
if(last->val > t->val){
flag = 1;
x = last; //记录非二叉搜索开始节点
y = t;
}
} else{
if(t->val < y->val){
y = t; //寻找最小的节点
}
}
}
last = t;
ldr(t->right);
}
}
void recoverTree(TreeNode* root) {
ldr(root);
swap(x->val, y->val);
}