6.1 二叉树的前、中、后序遍历
144.、二叉树的前序遍历(中左右)
LeetCode:114、二叉树的前序遍历
(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> result;
traversal(root, result);
return result;
}
};
(2)迭代法
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;
}
};
(3)统一迭代格式
class Solution {
public:
// 统一的迭代格式
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if (NULL == root)
return res;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
st.push(node); // 中
st.push(NULL);
} else {
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
94、二叉树的中序遍历(左中右)
LeetCode: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> result;
traversal(root, result);
return result;
}
};
(2)迭代法
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(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
st.pop();
result.push_back(cur->val); // 中
cur = cur->right; // 右
}
}
return result;
}
};
(3)统一迭代格式
class Solution {
public:
// 统一迭代格式
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if (NULL == root)
return res;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
if (node->right) st.push(node->right); // 右
st.push(node); // 中
st.push(NULL);
if (node->left) st.push(node->left); // 左
} else {
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
145、二叉树的后序遍历(左右中)
LeetCode: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> result;
traversal(root, result);
return result;
}
};
(2)迭代法
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;
}
};
(3)统一迭代格式
class Solution {
public:
// 统一迭代格式
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if (NULL == root)
return res;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
st.push(node); // 中
st.push(NULL);
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
} else {
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
589、N叉树前序遍历
LeetCode:589、N叉树前序遍历
class Solution {
public:
void traversal(Node* cur, vector<int>& vec) {
if (NULL == cur) return;
vec.push_back(cur->val);
for (int i = 0; i < cur->children.size(); i++) {
traversal(cur->children[i], vec);
}
}
vector<int> preorder(Node* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
590、N叉树的后序遍历
LeetCode:590、N叉树的后序遍历
class Solution {
public:
// 递归
void traversal(Node* cur, vector<int>& vec) {
if (NULL == cur) return;
for (int i = 0; i < cur->children.size(); i++) {
traversal(cur->children[i], vec);
}
vec.push_back(cur->val);
}
vector<int> postorder(Node* root) {
vector<int> res;
traversal(root, res);
return res;
}
};
6.2 二叉树的层序遍历
102、二叉树的层序遍历
LeetCode:102、二叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if (NULL == root)
return result;
que.push(root);
while (!que.empty()) {
int size = que.size();
vector<int> cur;
// 这里一定要使用固定的大小的size,不要使用que.size()
// 因为que.size()是在不断变化的
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
cur.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(cur);
}
return result;
}
};
107、二叉树的层序遍历 II
LeetCode:107、二叉树的层序遍历||
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> que;
if (NULL == root) return res;
que.push(root);
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);
}
res.push_back(vec);
}
reverse(res.begin(), res.end()); // 在这里翻转一下即可
return res;
}
};
637、二叉树的层平均值
LeetCode:637、二叉树的层平均值
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> res;
queue<TreeNode*> que;
if (NULL == root)
return res;
que.push(root);
while (!que.empty()) {
int size = que.size();
double sum = 0; // // 统计每⼀层的和
for(int i = 0; i < size; i++) {
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 / size); // 将每⼀层均值放进结果集
}
return res;
}
};
429、N 叉树的层序遍历
LeetCode:N叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
queue<Node*> que;
if (NULL == root)
return res;
que.push(root);
while (!que.empty()) {
int size = que.size();
vector<int> vec;
for (int i = 0; i < size; i++) {
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、在每个树行中找最大值
LeetCode:515、在每个树行中找最大值
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> res;
queue<TreeNode*> que;
if (NULL == root) return res;
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();
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、填充每个节点的下一个右侧节点指针
LeetCode:116、填充每个节点的下一个右侧节点指针
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (NULL == root) return root;
que.push(root);
while (!que.empty()) {
int size = que.size();
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
if (0 == i) {
nodePre = que.front(); // 取出⼀层的头结点
que.pop();
node = nodePre; // 这一行不能少
} else {
node = que.front();
que.pop();
nodePre->next = node; // 本层前⼀个节点next指向本节点
nodePre = node; // 这里有点类似双指针的感觉
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL; // 本层最后⼀个节点指向NULL
}
return root;
}
};
117、填充每个节点的下一个右侧节点指针 II
LeetCode:117、填充每个节点的下一个右侧节点指针 ||
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (NULL == root) return root;
que.push(root);
while (!que.empty()) {
int size = que.size();
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
if (0 == i) {
nodePre = que.front();
que.pop();
node = nodePre;
} else {
node = que.front();
que.pop();
nodePre->next = node;
nodePre = node;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL;
}
return root;
}
};
6.3 翻转二叉树
226、翻转二叉树
LeetCode:226、翻转二叉树
(1)基于前序-递归
class Solution {
public:
// 基于前序遍历的递归法
void swapTree(TreeNode* cur) {
if (NULL == cur)
return;
swap(cur->left, cur->right); // 中
swapTree(cur->left); // 左
swapTree(cur->right); // 右
}
TreeNode* invertTree(TreeNode* root) {
swapTree(root);
return root;
}
};
(2)基于前序-迭代
class Solution {
public:
// 基于前序遍历的迭代法
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if (NULL == root)
return root;
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;
}
};
(3)基于层序遍历
class Solution {
public:
// 层序遍历
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> que;
if (NULL == root) return root;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
swap(node->left, node->right);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return root;
}
};
- 注意:其实这里不用 for 循环也能翻转成功,因为我们不必要求把元素一层一层的堆放起来。我们只是一层一层的访问(…只可意会吧…)
class Solution {
public:
// 层序遍历
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> que;
if (NULL == root) return root;
que.push(root);
while (!que.empty()) {
TreeNode* node = que.front();
que.pop();
swap(node->left, node->right);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
return root;
}
};
6.4 对称二叉树
101、对称二叉树
LeetCode:101、对称二叉树
(1)递归法
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;
else {
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
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);
}
};
(2)迭代法 - 队列
class Solution {
public:
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> que;
if (NULL == root) return true;
// 注意:这里加入队列一定是成对加入的
// 所以在加入队列前,一定不要判断 是否为空,否则会出现不成对的情况
// 下面也一样
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 == NULL && rightNode == NULL) continue;
else if (leftNode != NULL && rightNode == NULL) return false;
else if (leftNode == NULL && rightNode != NULL) return false;
else if (leftNode->val != rightNode->val) return false;
else {
que.push(leftNode->left); // 加入左节点左孩子
que.push(rightNode->right); // 加入右节点右孩子
que.push(leftNode->right); // 加入左节点右孩子
que.push(rightNode->left); // 加入右节点左孩子
}
}
return true;
}
};
(3)迭代法 - 栈
基本和上面一样
class Solution {
public:
bool isSymmetric(TreeNode* root) {
stack<TreeNode*> st;
if (NULL == root) return true;
st.push(root->left);
st.push(root->right);
while (!st.empty()) {
TreeNode* rightNode = st.top(); st.pop();
TreeNode* leftNode = st.top(); st.pop();
if (leftNode == NULL && rightNode == NULL) continue;
else if (leftNode != NULL && rightNode == NULL) return false;
else if (leftNode == NULL && rightNode != NULL) return false;
else if (leftNode->val != rightNode->val) return false;
else {
st.push(leftNode->left);
st.push(rightNode->right);
st.push(leftNode->right);
st.push(rightNode->left);
}
}
return true;
}
};
100、相同的树
LeetCode:100.相同的树
- 递归法
class Solution {
public:
// 递归
bool compareTree(TreeNode* left, TreeNode* right) {
if (left == NULL && right == NULL) return true;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right != NULL) return false;
else if (left->val != right->val) return false;
else {
bool res_left = compareTree(left->left, right->left);
bool res_right = compareTree(left->right, right->right);
return res_left && res_right;
}
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return compareTree(p, q);
}
};
572、另一棵树的子树
LeetCode:572、另一棵树的子树
class Solution {
public:
bool isSame(TreeNode* left, TreeNode* right) {
if (left == NULL && right == NULL) return true;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right != NULL) return false;
else if (left->val != right->val) return false;
else {
bool resLeft = isSame(left->left, right->left);
bool resRight = isSame(left->right, right->right);
return resLeft && resRight;
}
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (root == NULL) return false;
if (isSame(root, subRoot)) return true;
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
};
6.5 二叉树的最大深度
104、二叉树的最大深度
LeetCode:104、二叉树的最大深度
(1)基于后序遍历的递归法
class Solution {
public:
// 递归 基于后序遍历(左右中)
int getHeight(TreeNode* node) {
if (NULL == node) return 0;
int leftHeight = getHeight(node->left);
int rightHeight = getHeight(node->right);
int height = 1 + max(leftHeight, rightHeight);
return height;
}
int maxDepth(TreeNode* root) {
return getHeight(root);
}
};
(2)基于层序遍历
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;
int depth = 0;
if (NULL == root) return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return depth;
}
};
559、N叉树的最大深度
LeetCode:559、N叉树的最大深度
(1)基于后序遍历的递归法
class Solution {
public:
int getDepth(Node* node) {
if (NULL == node) return 0;
int depth = 0;
for (int i = 0; i < node->children.size(); i++) {
depth = max(depth, getDepth(node->children[i]));
}
return depth + 1;
}
int maxDepth(Node* root) {
return getDepth(root);
}
};
(2)基于层序遍历
class Solution {
public:
int maxDepth(Node* root) {
queue<Node*> que;
int depth = 0;
if (NULL == root) return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; i++) {
Node* node = que.front();
que.pop();
for (int j = 0; j < node->children.size(); j++) {
que.push(node->children[j]);
}
}
}
return depth;
}
};
6.6 二叉树的最小深度
111、二叉树的最小深度
LeetCode:111.二叉树的最小深度
(1)基于后序遍历
class Solution {
public:
int getDepth(TreeNode* node) {
if (node == NULL) return 0;
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
// 中
// 当一个左子树为空,右不为空,这时并不是最低点
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
// 当一个右子树为空,左不为空,这时并不是最低点
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
}
int minDepth(TreeNode* root) {
return getDepth(root);
}
};
(2)基于层序遍历
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录最小深度
for (int i = 0; i < size; i++) {
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 depth;
}
}
}
return depth;
}
};
6.7 完全二叉树的节点个数
222、完全二叉树的节点个数
LeetCode:222.完全二叉树的节点个数
(1)当作普通二叉树:后序遍历递归
class Solution {
public:
// 当作普通二叉树来计算节点:后序递归
int getNum(TreeNode* node) {
if (node == NULL) return 0;
int leftNum = getNum(node->left);
int rightNum = getNum(node->right);
return 1 + leftNum + rightNum;
}
int countNodes(TreeNode* root) {
return getNum(root);
}
};
(2)当作普通二叉树:层序遍历
class Solution {
public:
int countNodes(TreeNode* root) {
int depth = 0;
queue<TreeNode*> que;
if (NULL == root)
return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
depth++;
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return depth;
}
};
(3)利用满二叉树的特性
class Solution {
public:
int getNum(TreeNode* node) {
if (node == NULL) return 0;
TreeNode* leftNode = node->left;
TreeNode* rightNode = node->right;
// 这里初始为0是有目的的,为了下面求指数方便
int leftheight = 0, rightheight = 0;
while (leftNode) {// 求左子树深度
leftNode = leftNode->left;
leftheight++;
}
while (rightNode) {// 求右子树深度
rightNode = rightNode->right;
rightheight++;
}
// 注意(2<<1) 相当于2^2,所以leftheight初始为0
if (leftheight == rightheight)
return (2 << leftheight) - 1;
leftheight = getNum(node->left);
rightheight = getNum(node->right);
return 1 + leftheight + rightheight;
}
int countNodes(TreeNode* root) {
return getNum(root);
}
};
6.8 平衡二叉树
110、平衡二叉树
LeetCode:110.平衡二叉树
- 基于后序遍历判断左右子树高度差是否大于1
class Solution {
public:
// 基于后序遍历
int getHeight(TreeNode* node) {
if (NULL == node) return 0;
// 左
int leftHeight = getHeight(node->left);
if (-1 == leftHeight) return -1;
// 右
int rightHeight = getHeight(node->right);
if (-1 == rightHeight) return -1;
// 中
if (abs(leftHeight - rightHeight) > 1)
return -1;
else
return 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
};
6.9 二叉树的所有路径
257、二叉树的所有路径
LeetCode:257.二叉树的所有路径
(1)基于前序遍历的递归法
class Solution {
private:
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
path.push_back(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中
// 这才到了叶子节点
if (cur->left == NULL && cur->right == NULL) {
string sPath;
for (int i = 0; i < path.size() - 1; i++) {
// to_string()函数:括号内的 数字 转化为 字符串
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;
}
};
6.10 左叶子之和
404、左叶子之和
LeetCode:404.左叶子之和
(1)基于后序遍历的递归法
class Solution {
public:
int traversal(TreeNode* node) {
if (node == NULL) return 0;
if (node->left == NULL && node->right == NULL) return 0;
int leftNum = traversal(node->left);
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL)
leftNum = node->left->val;
int rightNum = traversal(node->right);
return leftNum + rightNum;
}
int sumOfLeftLeaves(TreeNode* root) {
return traversal(root);
}
};
(2)基于前序遍历的迭代法
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
int result = 0;
stack<TreeNode*> st;
if (NULL == root) return 0;
st.push(root);
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->right) st.push(node->right);
if (node->left) st.push(node->left);
}
return result;
}
};
(3)基于层序遍历法
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
int result = 0;
queue<TreeNode*> que;
if (NULL == root) return 0;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL)
result += node->left->val;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
6.11 找树左下角的值
513、找树左下角的值
LeetCode:513、找树左下角的值
(1)递归法
class Solution {
public:
int maxDepth = INT_MIN;
int result;
void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) {
if (depth > maxDepth) {
maxDepth = depth;
result = root->val;
}
return;
}
if (root->left) {
depth++;
traversal(root->left, depth);
depth--; // 回溯
}
if (root->right) {
depth++;
traversal(root->right, depth);
depth--; // 回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
};
(2)基于层序遍历
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
int result = 0;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (i == 0) result = node->val; // 记录最后一行第一个元素
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
6.12 路径总和
112、路径总和
LeetCode:112.路径总和
(1)基于《二叉树所有路径》进行修改
class Solution {
public:
int res = -1;
void traversal(TreeNode* node, vector<int>& path, int& targetSum) {
path.push_back(node->val);
if (node->left == NULL && node->right == NULL) {
int sum = 0;
for (int i = 0; i < path.size(); i++) {
sum += path[i];
}
if (sum == targetSum) {
res = 1;
return;
}
}
if (node->left) {
traversal(node->left, path, targetSum);
path.pop_back();
}
if (node->right) {
traversal(node->right, path, targetSum);
path.pop_back();
}
}
bool hasPathSum(TreeNode* root, int targetSum) {
vector<int> path;
if (NULL == root)
return false;
traversal(root, path, targetSum);
return res == 1 ? true : false;
}
};
(2)递归法
class Solution {
private:
bool traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right)
return count == 0; // 遇到叶子节点,判断计数器是否为0
if (cur->left) { // 左
count -= cur->left->val; // 递归,处理节点;
if (traversal(cur->left, count)) return true;
count += cur->left->val; // 回溯,撤销处理结果
}
if (cur->right) { // 右
count -= cur->right->val; // 递归,处理节点;
if (traversal(cur->right, count)) return true;
count += cur->right->val; // 回溯,撤销处理结果
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int sum) {
if (root == NULL) return false;
// 这里一定要减掉root节点的值
return traversal(root, sum - root->val);
}
};
(3)基于前序遍历的迭代法
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
stack<pair<TreeNode*, int>> st;
if (NULL == root) return false;
st.push(pair<TreeNode*, int>(root, root->val));
while (!st.empty()) {
pair<TreeNode*, int> pari_node = st.top();
st.pop();
TreeNode* node = pari_node.first;
int val = pari_node.second;
if (node->left == NULL && node->right == NULL) {
if (val == targetSum)
return true;
else
continue;
}
if (node->left)
st.push(pair<TreeNode*, int>(node->left, val + node->left->val));
if (node->right)
st.push(pair<TreeNode*, int>(node->right, val + node->right->val));
}
return false;
}
};
113、路径总和 II
LeetCode:113.路径总和 II
(1)基于《二叉树所有路径》修改
class Solution {
public:
void traversal(TreeNode* node, int targetSum, vector<int>& path, vector<vector<int>>& result) {
path.push_back(node->val);
if (node->left == NULL && node->right == NULL) {
int sum = 0;
for (int i = 0; i < path.size(); i++) {
sum += path[i];
}
if (sum == targetSum)
result.push_back(path);
return;
}
if (node->left) {
traversal(node->left, targetSum, path, result);
path.pop_back();
}
if (node->right) {
traversal(node->right, targetSum, path, result);
path.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
vector<vector<int>> result;
if (root == NULL) return result;
traversal(root, targetSum, path, result);
return result;
}
};
(2)迭代法
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void traversal(TreeNode* node, int count) {
path.push_back(node->val);
if (node->left == NULL && node->right == NULL) {
if (count == 0)
result.push_back(path);
return;
}
if (node->left) {
count -= node->left->val;
traversal(node->left, count);
count += node->left->val;
path.pop_back();
}
if (node->right) {
count -= node->right->val;
traversal(node->right, count);
count += node->right->val;
path.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if (root == NULL) return result;
traversal(root, targetSum - root->val);
return result;
}
};
6.13 从中序和后序遍历构造二叉树
106、从中序和后序遍历序列构造二叉树
LeetCode:106、从中序和后序遍历序列构造二叉树
- 完整版
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0) return NULL;
// 后序遍历数组最后一个元素,就是当前的中间节点
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (postorder.size() == 1) return root;
// 找到中序遍历的切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// postorder 舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 切割后序数组
// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
// [0, leftInorder.size)
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
// [leftInorder.size(), end)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
- 精简版
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());
}
};
105、从前序与中序遍历序列构造二叉树
LeetCode:105、从前序与中序遍历序列构造二叉树
- 完整版
class Solution {
public:
TreeNode* traversal(vector<int> preorder, vector<int> inorder) {
if (preorder.size() == 0) return NULL;
int val = preorder[0];
TreeNode* root = new TreeNode(val);
if (preorder.size() == 1) return root;
int index;
for (index = 0; index < inorder.size(); index++) {
if (inorder[index] == val)
break;
}
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + 1 + index);
vector<int> rightPreorder(preorder.begin() + 1 + index, preorder.end());
root->left = traversal(leftPreorder, leftInorder);
root->right = traversal(rightPreorder, rightInorder);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return NULL;
return traversal(preorder, inorder);
}
};
- 精简版
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, int preorderBegin, int preorderEnd,
vector<int>& inorder, int inorderBegin, int inorderEnd) {
if (preorderEnd == preorderBegin) return NULL;
int val = preorder[preorderBegin];
TreeNode* root = new TreeNode(val);
if (preorderEnd - preorderBegin == 1) return root;
int index;
for (index = inorderBegin; index < inorderEnd; index++) {
if (inorder[index] == val)
break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = index;
int rightInorderBegin = index + 1;
int rightInorderEnd = inorderEnd;
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = leftPreorderBegin + leftInorderEnd - leftInorderBegin;
int rightPreorderBegin = leftPreorderEnd;
int rightPreorderEnd = preorderEnd;
root->left = traversal(preorder, leftPreorderBegin, leftPreorderEnd,
inorder, leftInorderBegin, leftInorderEnd);
root->right = traversal(preorder, rightPreorderBegin, rightPreorderEnd,
inorder, rightInorderBegin, rightInorderEnd);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return NULL;
return traversal(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}
};
6.14 最大二叉树
654、最大二叉树
LeetCode:654、最大二叉树
(1)完整版
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
return node;
}
// 找到数组中最大的值和对应的下标
int maxValue = 0;
int maxValueIndex = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > maxValue) {
maxValue = nums[i];
maxValueIndex = i;
}
}
node->val = maxValue;
// 最大值所在的下标左区间 构造左子树
if (maxValueIndex > 0) {
vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
}
// 最大值所在的下标右区间 构造右子树
if (maxValueIndex < (nums.size() - 1)) {
vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
}
return node;
}
};
(2)精简版
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());
}
};
6.15 合并二叉树
617、合并二叉树
LeetCode:617、合并二叉树
(1)基于前序遍历
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;
}
};
(2)新建一个二叉树
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;
}
};
6.16 二叉搜索树中的搜索
700、二叉搜索树中的搜索
LeetCode:700、二叉搜索树中的搜索
(1)递归法
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root == NULL || root->val == val) return root;
TreeNode* node = NULL;
if (val < root->val) node = searchBST(root->left, val);
if (val > root->val) node = searchBST(root->right, val);
return node;
}
};
(2)迭代法
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while (root != NULL) {
if (val < root->val) root = root->left;
else if (val > root->val) root = root->right;
else return root;
}
return NULL;
}
};
6.17 验证二叉搜索树
98、验证二叉搜索树
LeetCode:98、验证二叉搜索树
(1)直白的解法:中序遍历,得到的数组升序
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;
}
};
(2)用maxValue来保存上一个节点的值
class Solution {
public:
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
bool isValidBST(TreeNode* root) {
if (root == NULL) return true;
bool left = isValidBST(root->left);
// 中序遍历,验证遍历的元素是不是从小到大
if (maxVal < root->val) maxVal = root->val;
else return false;
bool right = isValidBST(root->right);
return left && right;
}
};
(3)用pre来记录上一个节点的信息
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;
}
};
6.18 二叉搜索树的最小绝对差
530、二叉搜索树的最小绝对差
LeetCode:530、二叉搜索树的最小绝对差
(1)直观的做法:先中序遍历,再比较
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:
int getMinimumDifference(TreeNode* root) {
vec.clear();
traversal(root);
if (vec.size() < 2) return 0;
int result = INT_MAX;
for (int i = 1; i < vec.size(); i++) { // 统计有序数组的最小差值
result = min(result, vec[i] - vec[i-1]);
}
return result;
}
};
(2)双指针法
class Solution {
private:
int result = INT_MAX;
TreeNode* pre = NULL;
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;
}
};
6.19 二叉搜索树中的众数
501、二叉搜索树中的众数
LeetCode:501.二叉搜索树中的众数
双指针法
class Solution {
public:
TreeNode* pre = NULL;
int count = 0, maxCount = 0;
vector<int> res;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->left);
if (pre == NULL) count = 1;
else if (cur->val == pre->val) count++;
else count = 1;
pre = cur;
if (count == maxCount) res.push_back(cur->val);
else if (count > maxCount) {
res.clear();
res.push_back(cur->val);
maxCount = count;
}
traversal(cur->right);
}
vector<int> findMode(TreeNode* root) {
traversal(root);
return res;
}
};
6.20 二叉树的最近公共祖先
236、二叉树的最近公共祖先
LeetCode:236、二叉树的最近公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == NULL || root == p || root == q) return root;
TreeNode* leftNode = lowestCommonAncestor(root->left, p, q);
TreeNode* rightNode = lowestCommonAncestor(root->right, p, q);
if (leftNode != NULL && rightNode != NULL) return root;
else if (leftNode == NULL && rightNode != NULL) return rightNode;
else if (leftNode != NULL && rightNode == NULL) return leftNode;
else return NULL;
}
};
6.21 二叉搜索树的最近公共祖先
235、二叉搜索树的最近公共祖先
LeetCode:235、二叉搜索树的最近公共祖先
- 递归法
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.22 二叉搜索树中的插入操作
701、二叉搜索树中的插入操作
LeetCode:701、二叉搜索树中的插入操作
- 递归法
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
if (val < root->val)
root->left = insertIntoBST(root->left, val);
else
root->right = insertIntoBST(root->right, 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;
}
};
6.23 删除二叉搜索树中的节点
450、删除二叉搜索树中的节点
LeetCode:450、删除二叉搜索树中的节点
- 删除节点分五种情况:
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == NULL) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
if (root->val == key) {
// 第二种情况:左右孩子都为空(叶子节点),
// 直接删除节点, 返回NULL为根节点
if (root->left == NULL && root->right == NULL) {
///! 内存释放
delete root;
return NULL;
}
// 第三种情况:其左孩子为空,右孩子不为空,
// 删除节点,右孩子补位 ,返回右孩子为根节点
else if (root->left == NULL) {
TreeNode* retNode = root->right;
///! 内存释放
delete root;
return retNode;
}
// 第四种情况:其右孩子为空,左孩子不为空,
// 删除节点,左孩子补位,返回左孩子为根节点
else if (root->right == NULL) {
TreeNode* retNode = root->left;
///! 内存释放
delete root;
return retNode;
}
// 第五种情况:左右孩子节点都不为空,
//则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
// 并返回删除节点右孩子为新的根节点。
else {
TreeNode* cur = root->right; // 找右子树最左面的节点
while(cur->left != NULL) {
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;
}
};
6.24 修剪二叉搜索树
669、修剪二叉搜索树
LeetCode:669、修建二叉树
- 递归法
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == NULL) return root;
if (root->val < low)
return trimBST(root->right, low, high);
else 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;
}
};
6.25 将有序数组转换为二叉搜索树
108、将有序数组转换为二叉搜索树
LeetCode:108、将有序数组转换为二叉搜索树
- 递归法
class Solution {
public:
TreeNode* traversal(vector<int>& nums, int left, int right) {
if (left > right) return NULL;
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;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return traversal(nums, 0, nums.size() - 1);
}
};
6.26 把二叉搜索树转换为累加树
538、把二叉搜索树转换为累加树
LeetCode:538、把二叉搜索树转换为累加树
class Solution {
public:
int pre = 0;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->right);
cur->val += pre;
pre = cur->val;
traversal(cur->left);
}
TreeNode* convertBST(TreeNode* root) {
traversal(root);
return root;
}
};