注:以下代码均为c++
数据结构的定义与创建:
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) {}
};
//由扩展先序序列构造二叉树
// 法1:输入数组
vector<int> t = {4,1,-1,-1,6,0,-1,-1,2,-1,-1}; //-1代表空
int i = 0;
void buildTree(TreeNode*& root){ //注意这里必须传引用
if(t[i] == -1) {
root = nullptr;
i++;
}
else{
root = new TreeNode(t[i]);
i++;
buildTree(root->left);
buildTree(root->right);
}
}
//法2:依次输入字符,其中'#'表示空字符
void buildTree(TreeNode*& root){
char x;
cin >> x;
if(x == '#')
root = nullptr;
else{
root = new TreeNode(x-'0');
buildTree(root->left);
buildTree(root->right);
}
}
1. 验证二叉搜索树
思路1:中序遍历有序
vector<int> list = {};
void InOrder(TreeNode* T){
if(T != NULL){
InOrder(T->left);
list.push_back(T->val);
InOrder(T->right);
}
}
bool isValidBST(TreeNode* root) {
InOrder(root);
for(int i = 0; i < list.size() - 1; i++){
if(list[i] >= list[i+1])
return false;
}
return true;
}
思路2:先序遍历,判断每个节点取值范围。
bool dfs(TreeNode *root, long long minv, long long maxv){
if(root == NULL)
return true;
if(root->val < minv || root->val > maxv)
return false;
return dfs(root->left, minv, root->val - 1ll) && dfs(root->right, root->val + 1ll, maxv);
//1ll:long long类型的1
//为什么用long long类型?因为节点值可能为int类型边界值,-1或+1会导致溢出。
}
bool isValidBST(TreeNode* root) {
return dfs(root, INT_MIN, INT_MAX); //先序,先判断根节点的取值范围,再判断其左右节点的取值范围。
}
2. 二叉树的中序遍历
//1.递归:系统帮助我们模拟栈
vector<int> result;
void inOrder(TreeNode* root){
if(root != NULL){ //注意不要忘记判空
inOrder(root->left);
result.push_back(root->val);
inOrder(root->right);
}
}
vector<int> inorderTraversal(TreeNode* root) {
inOrder(root);
return result;
}
//2.手动写栈
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
TreeNode* p = root;
while(p || stk.size()){
//1.一路向左入栈
while(p){
stk.push(p);
p = p->left;
}
//2.栈顶元素出栈输出
p = stk.top();
stk.pop();
res.push_back(p->val);
//3.p指向右子树(重复以上步骤)
p = p->right;
}
return res;
}
3. 对称二叉树
思路1:递归
//1. 法1:递归
bool isequal(TreeNode* left, TreeNode* right) {
if(left && right)
return left->val == right->val && isequal(left->right, right->left) && isequal(left->left, right->right);
else{
if(left == NULL && right == NULL)
return true;
else
return false;
}
}
bool isSymmetric(TreeNode* root) {
if(root)
return isequal(root->left, root->right);
else
return true;
}
思路2:迭代
中序遍历,左面:左中右,右面:右中左,
若值全部一一对应返回true,否则返回false
// 2. 法2:迭代
//中序遍历,左面:左中右,右面:右中左,若值全部一一对应返回true,否则返回false
bool isSymmetric(TreeNode* root) {
if(root == NULL)
return true;
stack<TreeNode*> stkleft, stkright;
TreeNode* l = root->left, *r = root->right;
while(l || stkleft.size() || r || stkright.size()){
while(l && r){
stkleft.push(l);
l = l->left;
stkright.push(r);
r = r->right;
}
//如果l和r一个为空一个不为空,返回false
if(l || r)
return false;
//否则比较其数值
l = stkleft.top();
stkleft.pop();
r = stkright.top();
stkright.pop();
if(l->val != r->val)
return false;
l = l->right;
r = r->left;
}
return true;
}
4. 从前序与中序遍历构造二叉树
思路:
//递归的思想。如何查找中序遍历中的root,建立哈希表将中序遍历中每个元素的值与其坐标对应。
unordered_map<int, int> pos;
TreeNode* dfs(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir){
if(pl > pr) return NULL; //注意判断边界
//1 先序遍历第一个节点为根节点
int val = preorder[pl];
TreeNode* root = new TreeNode(val);
//2 找到根节点在中序遍历的位置,根节点前面为左子树,右面为右子树,递归
int i = pos[val];
int left_len = i-1-il;
root->left = dfs(preorder, inorder, pl+1, pl+1+left_len, il, i-1);
root->right = dfs(preorder, inorder, pl+1+left_len+1, pr, i+1, ir);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = inorder.size();
for(int i = 0; i < n; i++)
pos[inorder[i]] = i; //值=坐标
return dfs(preorder, inorder, 0, n-1, 0, n-1);
}片
5. 二叉树的层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res; //结果
if(root == NULL) return res;
queue<TreeNode*> q; //定义队列存储每行的元素
q.push(root);
while(q.size()){
int len = q.size();
vector<int> level;
for(int i = 0; i < len; i++){ //分别取每行元素,并把其左右孩子放进队列(即下一行)
TreeNode* t = q.front();
q.pop();
level.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
res.push_back(level);
}
return res;
}
6. 二叉树是最近公共祖先
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL || root == p || root == q)
return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left == NULL) return right;
if(right == NULL) return left;
return root;
}
7. 二叉树的直径
思路:
int ans = 0;
//本质:后序遍历,返回从当前节点向下走的最长路径
int dfs(TreeNode* root){
if(root == NULL) return 0;
int left = dfs(root->left);
int right = dfs(root->right);
ans = max(left + right, ans);
return max(left + 1, right + 1);
}
int diameterOfBinaryTree(TreeNode* root) {
dfs(root);
return ans;
}
8. 二叉树中的最大路径和
思路:此题与上一题类似,递归求解。
int ans = INT_MIN;
//本质:后序遍历,返回从当前节点向下走的最大路径和
int dfs(TreeNode* root){
if(root == NULL) return 0;
int left = dfs(root->left);
int right = dfs(root->right);
ans = max(left + right + root->val, ans);
return max(0, root->val + max(left, right));
}
int maxPathSum(TreeNode* root) {
dfs(root);
return ans;
}
9. 二叉搜索树迭代器
//本质是一个中序遍历
class BSTIterator {
public:
stack<TreeNode*> stk;
BSTIterator(TreeNode* root) {
while(root){
stk.push(root);
root = root->left;
}
}
int next() {
TreeNode* p = stk.top();
stk.pop();
int res = p->val;
p = p->right;
while(p){
stk.push(p);
p = p->left;
}
return res;
}
bool hasNext() {
return !stk.empty();
}
};