二叉树
1.二叉树的中序遍历
二叉树的中序遍历
中序遍历:左中右,可以用递归来实现,递归终止条件是root为空
push_back的动作与遍历的顺序有关:
遍历左 + push_back + 遍历右 ==> 中序遍历;
push_back + 遍历左 + 遍历右 ==> 前序遍历;
遍历左 + 遍历右 + push_back ==> 后序遍历;
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> ans;
vector<int> inorderTraversal(TreeNode* root) {
if (root == nullptr) return ans;
if (root->left != nullptr) inorderTraversal(root->left);
ans.push_back(root->val);
if (root->right != nullptr) inorderTraversal(root->right);
return ans;
}
};
2.二叉树的最大深度
二叉树的最大深度
可以用深度优先搜索来实现,时间复杂度o(n), 空间复杂度o(h),h表示二叉树高度。递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度。
也可以用广度优先搜索,用queue来实现,
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
3.翻转二叉树
翻转二叉树
翻转二叉树,可以用递归来实现,递归终止条件是root为空,抽象的将root->left 和 root->right 分别看作两个整体,只需要交换他们翻转后的结果即可
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == nullptr || (root->left == nullptr && root->right == nullptr))
return root;
auto tmp = invertTree(root->left);
root->left = invertTree(root->right);
root->right = tmp;
return root;
}
};
4.对称二叉树
对称二叉树
依旧可以用递归来解答该问题,
1.递归终止条件是root == nullptr那么return true
递归函数中可以分为以下几种情况:
1.左空右不为空,return false;
2.左不为空右空,return false;
3.左空右空,return true
4.都不为空,那么仔细观察,左右子树是不相等的,左子树的右子树 等于 右子树的左子树:root->left->right == root->right->left;
同理,左子树的左子树,等于右子树的右子树 :root->left->left == root->right->right;
并且,当前层root->left->val == root->right->val;
4.判断完当前层,依次判断左子树,右子树
则,构造一个函数,输入参数为(左子树,右子树),按照以上几种情况分别判断
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool check(TreeNode* left, TreeNode* right) {
if (left == nullptr && right == nullptr) return true;
if (left == nullptr || right == nullptr) return false;
return (left->val == right->val && check(left->left, right->right) && check(left->right, right->left));
}
bool isSymmetric(TreeNode* root) {
return check(root, root);
}
};
5.二叉树的直径
这道题可以转化为求二叉树左右子树高度和,我们需要一个全局遍历去维护左右子树高度和的最大值。每次递归的返回值是以当前节点为根节点的子树最大深度。
特别需要注意的点:这道题虽然是求路径,按题目中描述4->3->2->1的路径长度只有3,但是在递归时,我们不能直接return 3,因为你不知道当前递归到二叉树的哪一层,是否为root,每一次都必须返回该节点为根的子树的深度,在最终的返回结果中再减1
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int ans = 0;
int diameterOfBinaryTree(TreeNode* root) {
dfs(root);
return ans - 1;
}
int dfs(TreeNode* root) {
if (root == nullptr) return 0;
//左子树的最大高度
int l = dfs(root->left);
//右子树的最大高度
int r = dfs(root->right);
//路径和([起点,终点]闭区间)
ans = max(l + r + 1, ans);
//加上以当前节点为根节点的高度1
return max(l, r) + 1;
}
};
6.将有序数组转换为二叉搜索树
二叉搜索树,又称之为二叉排序树(二叉查找树),它或许是一棵空树,或许是具有以下性质的二叉树:
- 若他的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别是二叉搜索树
- 二叉搜索树的中序遍历是升序序列
平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1。
根据中序遍历+平衡这两个条件构建出的树也是不唯一的。
- 可以选择中间数字作为二叉搜索树的根节点,分给左右子树的数字个数相同或只相差 1,可以使得树保持平衡。
- 如果数组长度是奇数,则根节点的选择是唯一的。
- 如果数组长度是偶数,则可以选择中间位置左边的数字作为根节点或者选择中间位置右边的数字作为根节点,选择不同的数字作为根节点则创建的平衡二叉搜索树也是不同的。
- 确定平衡二叉搜索树的根节点之后,其余的数字分别位于平衡二叉搜索树的左子树和右子树中,左子树和右子树分别也是平衡二叉搜索树,因此可以通过递归的方式创建平衡二叉搜索树。
个人习惯,偶数情况下,每次以左侧元素为根节点
时间复杂度:O(n),其中 n 是数组的长度。每个数字只访问一次。
空间复杂度:O(logn),其中 n 是数组的长度。空间复杂度不考虑返回值,因此空间复杂度主要取决于递归栈的深度,递归栈的深度是 O(logn)。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
int n = nums.size();
return dfs(nums, 0, n - 1);
}
TreeNode* dfs(vector<int>& nums, int l, int r) {
if (l > r) return nullptr;
int mid = (l + r) / 2;
TreeNode* ans = new TreeNode(nums[mid]);
ans->left = dfs(nums, l, mid - 1);
ans->right = dfs(nums, mid + 1, r);
return ans;
}
};