- 理论基础
【1】分类
满二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/8311a2329816c670834e1e9168896797.png)
完全二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/dee892ff7934680d5ca7923befbbcbb4.png)
优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。
二叉搜素树
![](https://i-blog.csdnimg.cn/blog_migrate/6e0d6a4985042bd83fb822b74eefb3ec.png)
二叉搜索树是有数值的,二叉搜索树是一个有序树。
平衡二叉搜素树(AVL)
![](https://i-blog.csdnimg.cn/blog_migrate/af43d73aacb7fe35efbe451ef13f549b.png)
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意我这里没有说unordered_map、unordered_set,unordered_map、unordered_map底层实现是哈希表。
【2】存储方式
(1)链式存储
![](https://i-blog.csdnimg.cn/blog_migrate/d874912b132452a4e7f1aae09e8982fa.png)
(2)顺序存储
![](https://i-blog.csdnimg.cn/blog_migrate/b1cfa28d2a3dd5094dfe246eb60382f3.png)
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
【3】定义
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
【4】遍历
a.深度优先遍历:先往深走,遇到叶子节点再往回走。
前序遍历(递归法,迭代法)
中序遍历(递归法,迭代法)
后序遍历(递归法,迭代法)
b.广度优先遍历:一层一层的去遍历。
层次遍历(迭代法)
![](https://i-blog.csdnimg.cn/blog_migrate/952cf97c97c43006c5037c793989c497.png)
之前我们讲栈与队列的时候,就说过栈其实就是递归的一种实现结构,也就说前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。
2.深度优先遍历
【1】二叉树的前序遍历144
(1)递归
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
vec.push_back(cur->val); // 中
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> re;
traversal(root, re);
return re;
}
};
(2)迭代
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (!root) return re;
st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
st.pop();
re.push_back(tmp->val);
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
}
return re;
}
};
(3)统一迭代
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
st.push(tmp);
st.push(NULL);
}
else {
st.pop();
tmp = st.top();
st.pop();
re.push_back(tmp->val);
}
}
return re;
}
};
【2】二叉树的中序遍历94
(1)递归
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
vec.push_back(cur->val); // 中
traversal(cur->right, vec); // 右
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>re;
traversal(root, re);
return re;
}
};
(2)迭代
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (!root) return re;
TreeNode* cur = root;
while (cur || !st.empty()) {
if (cur) {
st.push(cur);
cur = cur->left;
}
else {
cur = st.top();
st.pop();
re.push_back(cur->val);
cur = cur->right;
}
}
return re;
}
};
(3)统一迭代
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
if (tmp->right) st.push(tmp->right);
st.push(tmp);
st.push(NULL);
if (tmp->left) st.push(tmp->left);
}
else {
st.pop();
tmp = st.top();
st.pop();
re.push_back(tmp->val);
}
}
return re;
}
};
【3】二叉树的后序遍历145
(1)递归
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
vec.push_back(cur->val); // 中
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int>re;
traversal(root, re);
return re;
}
};
(2)迭代
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (!root) return re;
st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
st.pop();
re.push_back(tmp->val);
if (tmp->left) st.push(tmp->left);
if (tmp->right) st.push(tmp->right);
}
reverse(re.begin(),re.end());
return re;
}
};
(3)统一迭代
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
st.push(tmp);
st.push(NULL);
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
}
else {
st.pop();
tmp = st.top();
st.pop();
re.push_back(tmp->val);
}
}
return re;
}
};
【4】前中后序遍历总结:
![](https://i-blog.csdnimg.cn/blog_migrate/d1153c7a8b1bb6d518436bdd6cfdba88.jpeg)
【5】左子叶之和404
递归
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == NULL) return 0;
int leftValue = 0;
if (root->left != NULL && root->left->left == NULL && root->left->right == NULL)
leftValue = root->left->val;
return leftValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
}
};
迭代
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
stack<TreeNode*> st;
if (root == NULL) return 0;
st.push(root);
int result = 0;
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL)
result += node->left->val;
//先左或者先右都可以
if (node->left) st.push(node->left);
if (node->right) st.push(node->right);
}
return result;
}
};
3.广度优先遍历
【1】二叉树的层序遍历102
![](https://i-blog.csdnimg.cn/blog_migrate/cbb796e7c79516689ae11acdfa4cc341.png)
递归
class Solution {
public:
void traversal(TreeNode* cur, vector<vector<int>>& re, int depth) {
if (!cur) return;
if (re.size() == depth) re.push_back(vector<int>());
re[depth].push_back(cur->val);
traversal(cur->left, re, depth + 1);
traversal(cur->right, re, depth + 1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> re;
int depth = 0;
traversal(root, re, depth);
return re;
}
};
迭代
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*>que;
vector<vector<int>> re;
if (root) que.push(root);
while (!que.empty()) {
vector<int>vec;
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
vec.push_back(tmp->val);
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
re.push_back(vec);
}
return re;
}
};
【2】二叉树的层序遍历II 107
题目描述:
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]
在return之前加如下一行:
reverse(re.begin(), re.end()); // 在这里反转一下数组即可
![](https://i-blog.csdnimg.cn/blog_migrate/6fe7f38075c9acce03b6e117de891a42.png)
【3】二叉树的右视图199
题目描述:
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
![](https://i-blog.csdnimg.cn/blog_migrate/3396965fc19b422805f0ce08a978f846.png)
层序遍历中,只记录每一行的最后一个值
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*>que;
vector<int> re;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
if (i == size - 1) re.push_back(tmp->val);
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
}
return re;
}
};
【4】二叉树的层平均值637
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*>que;
vector<double> re;
if (root) que.push(root);
while (!que.empty()) {
double sum = 0.0;
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
sum += (double)tmp->val;
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
re.push_back(sum/size);
}
return re;
}
};
【5】N叉树的层序遍历429
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*>que;
vector<vector<int>> re;
if (root) que.push(root);
while (!que.empty()) {
vector<int>vec;
int size = que.size();
for (int i = 0; i < size; ++i) {
Node* tmp = que.front();
que.pop();
vec.push_back(tmp->val);
for (int j = 0; j < tmp->children.size(); ++j) {
if (tmp->children[j]) que.push(tmp->children[j]);
}
}
re.push_back(vec);
}
return re;
}
};
【6】在每个树行中找最大值515
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
queue<TreeNode*>que;
vector<int> re;
if (root) que.push(root);
while (!que.empty()) {
int max = INT32_MIN;
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
max = max > tmp->val ? max : tmp->val;
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
re.push_back(max);
}
return re;
}
};
【7】找树左下角的值513
递归
class Solution {
public:
int maxLen = INT_MIN;
int maxleftValue;
void traversal(TreeNode* root, int leftLen) {
if (root->left == NULL && root->right == NULL) {
if (leftLen > maxLen) {
maxLen = leftLen;
maxleftValue = root->val;
}
return;
}
if (root->left) {
traversal(root->left, leftLen + 1); // 隐藏着回溯
}
if (root->right) {
traversal(root->right, leftLen + 1); // 隐藏着回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return maxleftValue;
}
};
层序+记录每行首节点
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*>que;
int re;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
if (i == 0) re = tmp->val;
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
}
return re;
}
};
(不彻底)翻转+层序
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*>que;
int re;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
re = tmp->val;
if (tmp->right) que.push(tmp->right);
if (tmp->left) que.push(tmp->left);
}
}
return re;
}
};
【8】填充每个节点的下一个右侧节点指针116/117
区别:完美二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/40764731057e4145d2a83f235de0c8bd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4eddedd5ca1e4bfc15dd5e880700536c.png)
单独记录i==0的节点
class Solution {
public:
Node* connect(Node* root) {
queue<Node*>que;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
Node* pre;
Node* node;
for (int i = 0; i < size; ++i) {
if (i == 0) {
pre = que.front();
que.pop();
node = pre;
}
else {
node = que.front();
que.pop();
pre->next = node;
pre = pre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return root;
}
};
【9】二叉树的最大深度104
层序
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*>que;
int depth = 0;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
}
return depth;
}
};
前序+回溯
class Solution {
public:
int re;
void getdepth(TreeNode* node, int depth) {
re = depth > re ? depth : re;
if (!node->left && !node->right) return;
if (node->left) {
depth++;
getdepth(node->left, depth);
depth--;
}
if (node->right) {
depth++;
getdepth(node->right, depth);
depth--;
}
}
int maxDepth(TreeNode* root) {
re = 0;
if (!root) return re;
getdepth(root, 1);
return re;
}
};
【10】二叉树的最小深度111
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*>que;
int depth = 0;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
if (!tmp->left && !tmp->right) return depth;
}
}
return depth;
}
};
【11】N叉树的最大深度559
class Solution {
public:
int maxDepth(Node* root) {
queue<Node*>que;
int depth = 0;
if (root) que.push(root);
while (!que.empty()) {
depth++;
int size = que.size();
for (int i = 0; i < size; ++i) {
Node* tmp = que.front();
que.pop();
for (int j = 0; j < tmp->children.size(); ++j) {
if (tmp->children[j]) que.push(tmp->children[j]);
}
}
}
return depth;
}
};
【12】完全二叉树的节点个数222
递归
class Solution {
private:
int getNodesNum(TreeNode* cur) {
if (cur == 0) return 0;
int leftNum = getNodesNum(cur->left);
int rightNum = getNodesNum(cur->right);
int treeNum = leftNum + rightNum + 1;
return treeNum;
}
public:
int countNodes(TreeNode* root) {
return getNodesNum(root);
}
};
递归简化
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == NULL) return 0;
return 1 + countNodes(root->left) + countNodes(root->right);
}
};
层序
class Solution {
public:
int countNodes(TreeNode* root) {
queue<TreeNode*>que;
int sum = 0;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
sum += size;
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
}
return sum;
}
};
完全二叉树
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr) return 0;
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftHeight = 0, rightHeight = 0;
while (left) {
left = left->left;
leftHeight++;
}
while (right) {
right = right->right;
rightHeight++;
}
if (leftHeight == rightHeight) {
// (2<<1) 相当于2^2,所以leftHeight初始为0
return (2 << leftHeight) - 1;
}
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
4.二叉树操作
【1】翻转二叉树226
![](https://i-blog.csdnimg.cn/blog_migrate/7041fada66fcd5260e37327b36a3c100.png)
【1】递归
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (!root) return root;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
【2】递归中序
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
invertTree(root->left);
swap(root->left, root->right);
//依然要遍历左孩子,因为中间节点已经翻转
invertTree(root->left);
return root;
}
};
【3】层序
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*>que;
if (root) que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* tmp = que.front();
que.pop();
swap(tmp->left, tmp->right);
if (tmp->left) que.push(tmp->left);
if (tmp->right) que.push(tmp->right);
}
}
return root;
}
};
【4】前序
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*>st;
if (!root) return root;
st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
st.pop();
swap(tmp->left, tmp->right);
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
}
return root;
}
};
【5】前序统一
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*>st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
swap(tmp->left, tmp->right);
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
st.push(tmp);
st.push(NULL);
}
else {
st.pop();
tmp = st.top();
st.pop();
}
}
return root;
}
};
【6】深度统一通法
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*>st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
st.push(tmp);
st.push(NULL);
}
else {
st.pop();
tmp = st.top();
st.pop();
//difference
swap(tmp->left, tmp->right);
}
}
return root;
}
};
【2】对称二叉树II 101
【1】层序
带null的层序遍历,判断每一层的vector是否对称
【2】递归
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false;
// 左右节点都不为空,且数值相同
bool outside = compare(left->left, right->right);
bool inside = compare(left->right, right->left);
bool isSame = outside && inside;
return isSame;
}
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
return compare(root->left, root->right);
}
};
【3】迭代队列
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
queue<TreeNode*> que;
que.push(root->left);
que.push(root->right);
while (!que.empty()) {
TreeNode* leftNode = que.front(); que.pop();
TreeNode* rightNode = que.front(); que.pop();
// 左右都空,对称
if (!leftNode && !rightNode) continue;
// 左右一个节点不为空,或者都不为空但数值不相同,返回false
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val)))
return false;
que.push(leftNode->left);
que.push(rightNode->right);
que.push(leftNode->right);
que.push(rightNode->left);
}
return true;
}
};
【4】迭代栈
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
stack<TreeNode*> st;
st.push(root->left);
st.push(root->right);
while (!st.empty()) {
TreeNode* leftNode = st.top(); st.pop();
TreeNode* rightNode = st.top(); st.pop();
if (!leftNode && !rightNode) continue;
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val)))
return false;
st.push(leftNode->left);
st.push(rightNode->right);
st.push(leftNode->right);
st.push(rightNode->left);
}
return true;
}
};
【3】平衡二叉树110
递归
class Solution {
public:
int getHeight(TreeNode* node) {
if (node == NULL) return 0;
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
};
迭代
class Solution {
public:
int getdepth(TreeNode* cur) {
stack<TreeNode*>st;
if (cur) st.push(cur);
int depth = 0;
int re = 0;
//后序统一
while (!st.empty()) {
TreeNode* tmp = st.top();
if (tmp) {
st.pop();
st.push(tmp);
st.push(NULL);
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
depth++;
}
else {
st.pop();
tmp = st.top();
st.pop();
depth--;
}
re = re > depth ? re : depth;
}
return re;
}
bool isBalanced(TreeNode* root) {
stack<TreeNode*>st;
if (!root) return true;
st.push(root);
while (!st.empty()) {
TreeNode* tmp = st.top();
st.pop();
if (abs(getdepth(tmp->left) - getdepth(tmp->right)) > 1)
return false;
if (tmp->right) st.push(tmp->right);
if (tmp->left) st.push(tmp->left);
}
return true;
}
};
110和104的getdepth函数可以互相转化
5.二叉树路径
【1】二叉树的所有路径257
递归+回溯
class Solution {
private:
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
path.push_back(cur->val);
if (cur->left == NULL && cur->right == NULL) {
string sPath;
for (int i = 0; i < path.size() - 1; i++) {
sPath += to_string(path[i]);
sPath += "->";
}
sPath += to_string(path[path.size() - 1]);
result.push_back(sPath);
return;
}
if (cur->left) {
traversal(cur->left, path, result);
path.pop_back(); // 回溯
}
if (cur->right) {
traversal(cur->right, path, result);
path.pop_back(); // 回溯
}
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
vector<int> path;
if (root == NULL) return result;
traversal(root, path, result);
return result;
}
};
递归
class Solution {
private:
void traversal(TreeNode* cur, string path, vector<string>& result) {
path += to_string(cur->val); // 中
if (cur->left == NULL && cur->right == NULL) {
result.push_back(path);
return;
}
if (cur->left) traversal(cur->left, path + "->", result); // 左
if (cur->right) traversal(cur->right, path + "->", result); // 右
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
string path;
if (root == NULL) return result;
traversal(root, path, result);
return result;
}
};
迭代
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
stack<TreeNode*> treeSt;
stack<string> pathSt;
vector<string> result;
if (root == NULL) return result;
treeSt.push(root);
pathSt.push(to_string(root->val));
while (!treeSt.empty()) {
TreeNode* node = treeSt.top(); treeSt.pop();
string path = pathSt.top(); pathSt.pop();
if (node->left == NULL && node->right == NULL) {
result.push_back(path);
}
if (node->right) {
treeSt.push(node->right);
pathSt.push(path + "->" + to_string(node->right->val));
}
if (node->left) {
treeSt.push(node->left);
pathSt.push(path + "->" + to_string(node->left->val));
}
}
return result;
}
};
【2】路径总和112
题目描述:
判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
递归
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
if (!root->left && !root->right && targetSum == root->val) return true;
return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}
};
迭代
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
stack<pair<TreeNode*, int>> st;
st.push(pair<TreeNode*, int>(root, root->val));
while (!st.empty()) {
pair<TreeNode*, int> node = st.top();
st.pop();
if (!node.first->left && !node.first->right && targetSum == node.second) return true;
if (node.first->right) {
st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
}
if (node.first->left) {
st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
}
}
return false;
}
};
【3】路径总和II 113
题目描述:
找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
// 递归函数不需要返回值,因为我们要遍历整个树
void traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为targetSum的路径
result.push_back(path);
return;
}
if (!cur->left && !cur->right) return ; // 遇到叶子节点而没有找到合适的边,直接返回
if (cur->left) { // 左 (空节点不遍历)
path.push_back(cur->left->val);
count -= cur->left->val;
traversal(cur->left, count); // 递归
count += cur->left->val; // 回溯
path.pop_back(); // 回溯
}
if (cur->right) { // 右 (空节点不遍历)
path.push_back(cur->right->val);
count -= cur->right->val;
traversal(cur->right, count); // 递归
count += cur->right->val; // 回溯
path.pop_back(); // 回溯
}
return ;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
result.clear();
path.clear();
if (root == nullptr) return result;
path.push_back(root->val); // 把根节点放进路径
traversal(root, targetSum - root->val);
return result;
}
};
6.构造二叉树
【1】从中序与后序遍历序列构造二叉树106
题目描述:
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
![](https://i-blog.csdnimg.cn/blog_migrate/b123f9d4c0254b3c602211c8ef3a1cf6.png)
class Solution {
private:
// 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
if (postorderBegin == postorderEnd) return NULL;
int rootValue = postorder[postorderEnd - 1];
TreeNode* root = new TreeNode(rootValue);
if (postorderEnd - postorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割后序数组
// 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
// 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
// 左闭右开的原则
return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
【2】从前序与中序遍历序列构造二叉树105
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
if (preorderBegin == preorderEnd) return NULL;
int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
TreeNode* root = new TreeNode(rootValue);
if (preorderEnd - preorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割前序数组
// 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
// 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
int rightPreorderEnd = preorderEnd;
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, preorder, leftPreorderBegin, leftPreorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (inorder.size() == 0 || preorder.size() == 0) return NULL;
// 参数坚持左闭右开的原则
return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
}
};
前序和中序可以唯一确定一颗二叉树。
后序和中序可以唯一确定一颗二叉树。
那么前序和后序可不可以唯一确定一颗二叉树呢?
前序和后序不能唯一确定一颗二叉树!,因为没有中序遍历无法确定左右部分,也就是无法分割。
【3】最大二叉树654
题目描述:
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
![](https://i-blog.csdnimg.cn/blog_migrate/d97c291bed56c6aa201d772f72a7f41f.png)
class Solution {
private:
// 在左闭右开区间[left, right),构造二叉树
TreeNode* traversal(vector<int>& nums, int left, int right) {
if (left >= right) return nullptr;
// 分割点下标:maxValueIndex
int maxValueIndex = left;
for (int i = left + 1; i < right; ++i) {
if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
}
TreeNode* root = new TreeNode(nums[maxValueIndex]);
// 左闭右开:[left, maxValueIndex)
root->left = traversal(nums, left, maxValueIndex);
// 左闭右开:[maxValueIndex + 1, right)
root->right = traversal(nums, maxValueIndex + 1, right);
return root;
}
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return traversal(nums, 0, nums.size());
}
};
【4】合并二叉树617
题目描述:
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
![](https://i-blog.csdnimg.cn/blog_migrate/0bba3deeb4b8975a6ed88f114d869135.png)
前序原树:
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
// 修改了t1的数值和结构
t1->val += t2->val; // 中
t1->left = mergeTrees(t1->left, t2->left); // 左
t1->right = mergeTrees(t1->right, t2->right); // 右
return t1;
}
};
前序新树:
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;
if (t2 == NULL) return t1;
// 重新定义新的节点,不修改原有两个树的结构
TreeNode* root = new TreeNode(0);
root->val = t1->val + t2->val;
root->left = mergeTrees(t1->left, t2->left);
root->right = mergeTrees(t1->right, t2->right);
return root;
}
};
迭代:
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;
if (t2 == NULL) return t1;
queue<TreeNode*> que;
que.push(t1);
que.push(t2);
while(!que.empty()) {
TreeNode* node1 = que.front(); que.pop();
TreeNode* node2 = que.front(); que.pop();
// 此时两个节点一定不为空,val相加
node1->val += node2->val;
// 如果两棵树左节点都不为空,加入队列
if (node1->left != NULL && node2->left != NULL) {
que.push(node1->left);
que.push(node2->left);
}
// 如果两棵树右节点都不为空,加入队列
if (node1->right != NULL && node2->right != NULL) {
que.push(node1->right);
que.push(node2->right);
}
// 当t1的左节点 为空 t2左节点不为空,就赋值过去
if (node1->left == NULL && node2->left != NULL) {
node1->left = node2->left;
}
// 当t1的右节点 为空 t2右节点不为空,就赋值过去
if (node1->right == NULL && node2->right != NULL) {
node1->right = node2->right;
}
}
return t1;
}
};
7.二叉搜索树
【1】二叉搜索树中的搜索700
题目描述:
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null
![](https://i-blog.csdnimg.cn/blog_migrate/6906289128ac2db9771f29af6cc831f4.png)
递归:
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == NULL || root->val == val) return root;
if (root->val > val) return searchBST(root->left, val);
if (root->val < val) return searchBST(root->right, val);
return NULL;
}
};
迭代:
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while (root != NULL) {
if (root->val > val) root = root->left;
else if (root->val < val) root = root->right;
else return root;
}
return NULL;
}
};
【2】验证二叉搜索树98
题目描述:
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
递归:
class Solution {
private:
vector<int> vec;
void traversal(TreeNode* root) {
if (root == NULL) return;
traversal(root->left);
vec.push_back(root->val); // 将二叉搜索树转换为有序数组
traversal(root->right);
}
public:
bool isValidBST(TreeNode* root) {
vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
traversal(root);
for (int i = 1; i < vec.size(); i++) {
// 注意要小于等于,搜索树里不能有相同元素
if (vec[i] <= vec[i - 1]) return false;
}
return true;
}
};
简化递归:
class Solution {
public:
TreeNode* pre = NULL; // 用来记录前一个节点
bool isValidBST(TreeNode* root) {
if (root == NULL) return true;
bool left = isValidBST(root->left);
if (pre != NULL && pre->val >= root->val) return false;
pre = root; // 记录前一个节点
bool right = isValidBST(root->right);
return left && right;
}
};
中序
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* cur = root;
TreeNode* pre = NULL; // 记录前一个节点
while (cur != NULL || !st.empty()) {
if (cur != NULL) {
st.push(cur);
cur = cur->left; // 左
} else {
cur = st.top(); // 中
st.pop();
if (pre != NULL && cur->val <= pre->val)
return false;
pre = cur; //保存前一个访问的结点
cur = cur->right; // 右
}
}
return true;
}
};
【3】二叉搜索树的最小绝对差530
题目描述:
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
递归
class Solution {
private:
int result = INT_MAX;
TreeNode* pre;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->left); // 左
if (pre != NULL) // 中
result = min(result, cur->val - pre->val);
pre = cur;
traversal(cur->right); // 右
}
public:
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
中序
class Solution {
public:
int getMinimumDifference(TreeNode* root) {
stack<TreeNode*> st;
int re=INT32_MAX;
TreeNode* cur = root;
TreeNode* pre = NULL;
while (cur != NULL || !st.empty()) {
if (cur != NULL) {
st.push(cur);
cur = cur->left; // 左
}
else {
cur = st.top(); // 中
st.pop();
if (pre)
re = re > (cur->val - pre->val) ? (cur->val - pre->val) : re;
pre = cur;
cur = cur->right; // 右
}
}
return re;
}
};
【4】二叉搜索树中的众数501
题目描述:
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
递归:
class Solution {
private:
int maxCount; // 最大频率
int count; // 统计频率
TreeNode* pre;
vector<int> result;
void searchBST(TreeNode* cur) {
if (cur == NULL) return ;
searchBST(cur->left); // 左
// 中
if (pre == NULL) { // 第一个节点
count = 1;
} else if (pre->val == cur->val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同
count = 1;
}
pre = cur; // 更新上一个节点
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push_back(cur->val);
}
if (count > maxCount) { // 如果计数大于最大值频率
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push_back(cur->val);
}
searchBST(cur->right); // 右
return ;
}
public:
vector<int> findMode(TreeNode* root) {
count = 0;
maxCount = 0;
TreeNode* pre = NULL; // 记录前一个节点
result.clear();
searchBST(root);
return result;
}
};
迭代
class Solution {
public:
vector<int> findMode(TreeNode* root) {
vector<int>re;
stack<TreeNode*>st;
int max = 0;
int cnt = 0;
TreeNode* cur = root;
TreeNode* pre = NULL;
while (cur || !st.empty()) {
if (cur) {
st.push(cur);
cur = cur->left;
}
else {
cur = st.top();
st.pop();
if (!pre) cnt = 1;
else if (pre->val == cur->val) cnt++;
else cnt = 1;
if (max == cnt) re.push_back(cur->val);
else if (cnt > max) {
max = cnt;
re.clear();
re.push_back(cur->val);
}
pre = cur;
cur = cur->right;
}
}
return re;
}
};
【5】二叉搜索树的最近公共祖先235
题目描述:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
![](https://i-blog.csdnimg.cn/blog_migrate/48519cf695f68bfd705dc21e5bca7f8b.png)
递归:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == q || root == p || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left != NULL && right != NULL) return root;
if (left == NULL) return right;
return left;
}
};
递归:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val > p->val && root->val > q->val) {
return lowestCommonAncestor(root->left, p, q);
} else if (root->val < p->val && root->val < q->val) {
return lowestCommonAncestor(root->right, p, q);
} else return root;
}
};
迭代:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root) {
if (root->val > p->val && root->val > q->val) {
root = root->left;
} else if (root->val < p->val && root->val < q->val) {
root = root->right;
} else return root;
}
return NULL;
}
};
【6】二叉树的最近公共祖先236
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == q || root == p || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left != NULL && right != NULL) return root;
if (left == NULL) return right;
return left;
}
};
【7】二叉搜索树中的插入操作701
递归:
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
if (root->val > val) root->left = insertIntoBST(root->left, val);
if (root->val < val) root->right = insertIntoBST(root->right, val);
return root;
}
};
递归:
class Solution {
private:
TreeNode* parent;
void traversal(TreeNode* cur, int val) {
if (cur == NULL) {
TreeNode* node = new TreeNode(val);
if (val > parent->val) parent->right = node;
else parent->left = node;
return;
}
parent = cur;
if (cur->val > val) traversal(cur->left, val);
if (cur->val < val) traversal(cur->right, val);
return;
}
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
parent = new TreeNode(0);
if (root == NULL) {
root = new TreeNode(val);
}
traversal(root, val);
return root;
}
};
迭代:
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
TreeNode* cur = root;
TreeNode* parent = root; // 这个很重要,需要记录上一个节点,否则无法赋值新节点
while (cur != NULL) {
parent = cur;
if (cur->val > val) cur = cur->left;
else cur = cur->right;
}
TreeNode* node = new TreeNode(val);
if (val < parent->val) parent->left = node;// 此时是用parent节点的进行赋值
else parent->right = node;
return root;
}
};
【8】删除二叉搜索树中的节点450
题目描述:
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
【1】递归:
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 第一种情况:没找到删除的节点,遍历到空节点直接返回了
if (root == nullptr) return root;
if (root->val == key) {
// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
if (root->left == nullptr && root->right == nullptr) {
///! 内存释放
delete root;
return nullptr;
}
// 第三种情况:其左孩子空,右孩子不空,删除节点,右孩子补位 ,返回右孩子为根节点
else if (root->left == nullptr) {
auto retNode = root->right;
///! 内存释放
delete root;
return retNode;
}
// 第四种情况:其右孩子空,左孩子不空,删除节点,左孩子补位,返回左孩子为根节点
else if (root->right == nullptr) {
auto retNode = root->left;
///! 内存释放
delete root;
return retNode;
}
// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
// 并返回删除节点右孩子为新的根节点。
else {
TreeNode* cur = root->right; // 找右子树最左面的节点
while(cur->left != nullptr) {
cur = cur->left;
}
cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
TreeNode* tmp = root; // 把root节点保存一下,下面来删除
root = root->right; // 返回旧root的右孩子作为新root
delete tmp; // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
return root;
}
}
if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
【2】迭代:
class Solution {
private:
// 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上
// 并返回目标节点右孩子为新的根节点
// 是动画里模拟的过程
TreeNode* deleteOneNode(TreeNode* target) {
if (target == nullptr) return target;
if (target->right == nullptr) return target->left;
TreeNode* cur = target->right;
while (cur->left) {
cur = cur->left;
}
cur->left = target->left;
return target->right;
}
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root;
TreeNode* cur = root;
TreeNode* pre = nullptr; // 记录cur的父节点,用来删除cur
while (cur) {
if (cur->val == key) break;
pre = cur;
if (cur->val > key) cur = cur->left;
else cur = cur->right;
}
if (pre == nullptr) { // 如果搜索树只有头结点
return deleteOneNode(cur);
}
// pre 要知道是删左孩子还是右孩子
if (pre->left && pre->left->val == key) {
pre->left = deleteOneNode(cur);
}
if (pre->right && pre->right->val == key) {
pre->right = deleteOneNode(cur);
}
return root;
}
};
【3】普通二叉树:
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root;
if (root->val == key) {
if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
return root->left;
}
TreeNode *cur = root->right;
while (cur->left) {
cur = cur->left;
}
swap(root->val, cur->val); // 这里第一次操作目标值:交换目标值其右子树最左面节点。
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};
【9】修剪二叉搜索树669
题目描述:
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
【1】递归:
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr) return nullptr;
if (root->val < low) return trimBST(root->right, low, high);
if (root->val > high) return trimBST(root->left, low, high);
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
return root;
}
};
【2】迭代:
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int L, int R) {
if (!root) return nullptr;
// 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
while (root != nullptr && (root->val < L || root->val > R)) {
if (root->val < L) root = root->right; // 小于L往右走
else root = root->left; // 大于R往左走
}
TreeNode *cur = root;
// 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
while (cur != nullptr) {
while (cur->left && cur->left->val < L) {
cur->left = cur->left->right;
}
cur = cur->left;
}
cur = root;
// 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
while (cur != nullptr) {
while (cur->right && cur->right->val > R) {
cur->right = cur->right->left;
}
cur = cur->right;
}
return root;
}
};
【10】将有序数组转换为二叉搜索树108
题目描述:
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足每个节点的左右两个子树的高度差的绝对值不超过 1 的二叉树。
【1】递归:
class Solution {
private:
TreeNode* traversal(vector<int>& nums, int left, int right) {
if (left > right) return nullptr;
int mid = left + ((right - left) / 2);
TreeNode* root = new TreeNode(nums[mid]);
root->left = traversal(nums, left, mid - 1);
root->right = traversal(nums, mid + 1, right);
return root;
}
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* root = traversal(nums, 0, nums.size() - 1);
return root;
}
};
【2】迭代:
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
if (nums.size() == 0) return nullptr;
TreeNode* root = new TreeNode(0); // 初始根节点
queue<TreeNode*> nodeQue; // 放遍历的节点
queue<int> leftQue; // 保存左区间下标
queue<int> rightQue; // 保存右区间下标
nodeQue.push(root); // 根节点入队列
leftQue.push(0); // 0为左区间下标初始位置
rightQue.push(nums.size() - 1); // nums.size() - 1为右区间下标初始位置
while (!nodeQue.empty()) {
TreeNode* curNode = nodeQue.front();
nodeQue.pop();
int left = leftQue.front(); leftQue.pop();
int right = rightQue.front(); rightQue.pop();
int mid = left + ((right - left) / 2);
curNode->val = nums[mid]; // 将mid对应的元素给中间节点
if (left <= mid - 1) { // 处理左区间
curNode->left = new TreeNode(0);
nodeQue.push(curNode->left);
leftQue.push(left);
rightQue.push(mid - 1);
}
if (right >= mid + 1) { // 处理右区间
curNode->right = new TreeNode(0);
nodeQue.push(curNode->right);
leftQue.push(mid + 1);
rightQue.push(right);
}
}
return root;
}
};
【11】把二叉搜索树转换为累加树538
题目描述:
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
![](https://i-blog.csdnimg.cn/blog_migrate/1880c871a8958fcb05be95d0a15ee3a8.png)
【1】递归:
class Solution {
private:
int pre = 0; // 记录前一个节点的数值
void traversal(TreeNode* cur) { // 右中左遍历
if (cur == NULL) return;
traversal(cur->right);
cur->val += pre;
pre = cur->val;
traversal(cur->left);
}
public:
TreeNode* convertBST(TreeNode* root) {
pre = 0;
traversal(root);
return root;
}
};
【2】迭代:
class Solution {
private:
int pre; // 记录前一个节点的数值
void traversal(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur != NULL || !st.empty()) {
if (cur != NULL) {
st.push(cur);
cur = cur->right; // 右
} else {
cur = st.top(); // 中
st.pop();
cur->val += pre;
pre = cur->val;
cur = cur->left; // 左
}
}
}
public:
TreeNode* convertBST(TreeNode* root) {
pre = 0;
traversal(root);
return root;
}
};