二叉树的前中后序遍历
前序遍历
前序遍历的访问和处理顺序是一致的,即先访问当前节点,再将该节点的左子树和右子树加入栈中。
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;
}
};
二叉树的层次遍历
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;
// 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
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;
}
};
反转二叉树
https://leetcode-cn.com/problems/invert-binary-tree/
把每个节点的左右孩子调换顺序就行了,前序遍历和后序遍历都可以,但是中序遍历不行,因为中序遍历的特性会使有的节点的左右孩子调换两次。
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(!root) return root;
TreeNode *tmp = root->left;
root->left = root->right;
root->right = tmp;
if(root->left) invertTree(root->left);
if(root->right) invertTree(root->right);
return root;
}
};
对称二叉树※
https://leetcode-cn.com/problems/symmetric-tree/submissions/
这道题一开始我想的是直接层次遍历,看看每层的数值是不是“回文”,后来发现是“回文”是对称二叉树的必要不充分条件。
这道题需要比较根节点的两个子树的是不是对称的,对于左子树来说遍历顺序可以是左右中,那么对于右子树来说遍历顺序是右左中,其实不算是严格的后序遍历。
例如:
1
/ \
2 2
/ \ / \
3 4 4 3
/ \ / \
5 6 6 5
左子树的左右中顺序遍历:56342
右子树的右左中顺序遍历:56342
所以可以用两个数组,分别将左右子树的按照刚才说的遍历顺序记录下来,然后对比是不是一样。
class Solution {
public:
vector<int> left;
vector<int> right;
bool isSymmetric(TreeNode* root) {
leftRightIn(root->left);
rightLeftIn(root->right);
if (left.size() != right.size()) {
return false;
}
for (int i = 0; i < left.size(); i++ ){
// cout << left[i] << " " << right[i] << endl;
if (left[i] != right[i]) {
return false;
}
}
return true;
}
void leftRightIn(TreeNode* root) { // 左右中
if (root == NULL) {
left.push_back(-1);
return ;
}
leftRightIn(root->left);
leftRightIn(root->right);
left.push_back(root->val);
}
void rightLeftIn(TreeNode* root) { // 右左中
if (root == NULL) {
right.push_back(-1);
return ;
}
rightLeftIn(root->right);
rightLeftIn(root->left);
right.push_back(root->val);
}
};
还有一种就是直接找到与该节点对称的节点,比较两个节点的值以及他们子树的值,就不用建立数组记录访问顺序了:
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);
}
};
迭代法可以用队列,但是注意不是层次访问,每次将左->左、右->右、左->右,右->左加入队列,每次取出一对进行比较:
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;
}
};
由于队列每次只是存储每一层的节点,且每次从队列中取出的节点是一对,对与对之间的顺序不用严格控制,所以可以把队列直接替换成栈也行。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == NULL) 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;
}
};
二叉树的最大深度
https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
递归法很简单
class Solution {
public:
int res = 0;
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
getdepth(root, 1);
return res;
}
void getdepth(TreeNode* root, int k) {
if (res < k) res = k;
if (root->left) getdepth(root->left, k + 1);
if (root->right) getdepth(root->right, k + 1);
}
};
如果要是迭代法就是使用层次遍历,计算以下有多少层
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
int res = 0;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
res ++;
int len = q.size();
for (int i = 0; i < len; i++ ) {
TreeNode* node = q.front();
q.pop();
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return res;
}
};
多叉树的深度
https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
class Solution {
public:
int maxDepth(Node* root) {
if (!root) return 0;
int res = 0;
queue<Node*> q;
q.push(root);
while (!q.empty()) {
res ++;
int len = q.size();
for (int i = 0; i < len; i ++) {
Node* node = q.front();
q.pop();
for (int j = 0; j < node->children.size(); j++ ) {
q.push(node->children[j]);
}
}
}
return res;
}
};
二叉树的最小深度
https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
用层次遍历,当遇到左右孩子都为空的节点(叶子节点)时就返回,
class Solution {
public:
int minDepth(TreeNode* root) {
if (!root) return 0;
int res = 0;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
res ++;
int len = q.size();
for (int i = 0; i < len; i++) {
TreeNode* node = q.front();
q.pop();
if (!node->left && !node->right) return res;
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return res;
}
};
二叉树的所有路径
https://leetcode-cn.com/problems/binary-tree-paths/
这道题就是一道回溯题,递归的出口就是遇到叶子节点,麻烦的一点就是整数转字符串,C++不能直接转
class Solution {
public:
vector<string> res;
vector<string> binaryTreePaths(TreeNode* root) {
string path = "";
backtracking(root, path);
return res;
}
void backtracking(TreeNode* root, string path) {
if (!root->left && !root->right) {
if (path != "") path += "->";
path += intToString(root->val);
res.push_back(path);
return ;
}
if (path != "") path += "->";
if (root->left) backtracking(root->left, path + intToString(root->val));
if (root->right) backtracking(root->right, path + intToString(root->val));
}
string intToString(int x) {
if (x == 0) return "0";
string str = "";
bool negative = 0;
if (x < 0) {
negative = 1;
x = -x;
}
while (x != 0) {
string tmp = "";
tmp += x % 10 + '0';
str = tmp + str;
x /= 10;
}
if (negative)
return "-" + str;
return str;
}
};
平衡二叉树
https://leetcode-cn.com/problems/balanced-binary-tree/
要保证所有的节点都是平衡二叉树,所以每层递归都要返回该节点的高度,让上一层递归去判断左右子树的高度差。
class Solution {
public:
bool isBalanced(TreeNode* root) {
if (!root) return true;
return level(root) != -1;
}
int level(TreeNode* root) {
if(!root) return 0;
int left = level(root->left);
if (left == -1) return -1;
int right = level(root->right);
if (right == -1) return -1;
return abs(left - right) > 1 ? -1 : max(left, right) + 1;
}
};