树的特点
最小连通图
无环
有且只有 n − 1 n-1 n−1 条边
树的建立方式
顺序存储
只适用于满n叉树,完全n叉树
1<<n
表示结点 2 n 2^n 2n- P4715 【深基16.例1】淘汰赛
cpp
void solve() {
cin >> n;
for (int i = 0; i<(1<<n); i++) {
cin >> value[i + (1 << n)];
}
结构体数组
使用整型存储父母和孩子的编号信息,结点的权值。
cpp
typedef struct node {
int w,l,r,f;
};
vector<node>nodes(109, node());
链式存储
比结构体数组存储更加灵活,不依赖结点编号,且给定输入,父子关系明确。
leetcode的给定输入格式
- 使用结构体存储结点信息,使用指针的形式存储父母和孩子的信息。
cpp
* 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) {}
图的存储方式
树作为一种特殊的图,完全可以沿用图的存储方式
以下均为例题
遍历树的应用
对于遍历的理解,和递归三部曲的理解。
-
226.翻转二叉树:后序遍历修改左右结点,注意需要设置中间值,不然会空指针异常。
* 101. 对称二叉树:操作两个结点进行遍历,使用后序遍历收集结果。
cpp
bool dfs(TreeNode*left,TreeNode*right){
if(!left&&right)return false;
if(left&&!right)return false;
if(!left&&!right)return true;
return left->val==right->val&&dfs(left->left,right->right)&&dfs(left->right,right->left);
}
bool isSymmetric(TreeNode* root) {
if(!root)return true;
return dfs(root->left,root->right);
}
- 104.二叉树的最大深度:后序遍历。
cpp
int dfs(TreeNode* root){
if(!root)return 0;
return max(dfs(root->left),dfs(root->right))+1;
}
int maxDepth(TreeNode* root) {
return dfs(root);
}
- 111.二叉树的最小深度:后序遍历,但是只有叶子结点才算深度,所以遍历空结点会干扰最后答案 ,干脆不遍历空结点,空结点设置为
INT_MAX
。终止条件也改为叶子结点。y
cpp
int dfs(TreeNode*root){
if(!root->left&&!root->right)return 1;
int left=INT_MAX,right=INT_MAX;
if(root->left)left=dfs(root->left);
if(root->right)right=dfs(root->right);
return min(left,right)+1;
}
int minDepth(TreeNode* root) {
if(!root)return 0;
return dfs(root);
}
222.完全二叉树的节点个数:后序遍历或者BFS。
cpp
int dfs(TreeNode*root){
if(!root)return 0;
return dfs(root->left)+dfs(root->right)+1;
}
int countNodes(TreeNode* root) {
return dfs(root);
}
- 110. 平衡二叉树:本质是比较高度 。可以用
pair<int,int>
分别表示子树的高度和子树是否满足平衡二叉树,也可以用特殊值-1
处理。
cpp
int dfs(TreeNode* root){
if(!root)return 0;
int left=dfs(root->left);
int right=dfs(root->right);
if(left==-1||right==-1)return -1;
if(left-right>=2||right-left>=2){
return -1;
}
return max(left,right)+1;
}
bool isBalanced(TreeNode* root) {
if(dfs(root)!=-1)return true;
return false;
}
- 257. 二叉树的所有路径:回溯,注意
to_string
函数的使用。还用了一点终止条件控制 和带条件的遍历。
cpp
vector<string>res;
void dfs(TreeNode* root,string s){
if(!root)return;
if(!root->left&&!root->right){
res.push_back(s);
}
if(root->left){
string tmp(s);
tmp+="->";
tmp+=to_string(root->left->val);
dfs(root->left,tmp);
}
if(root->right){
string tmp(s);
tmp+="->";
tmp+=to_string(root->right->val);
dfs(root->right,tmp);
}
}
vector<string> binaryTreePaths(TreeNode* root) {
string s;
s+=to_string(root->val);
dfs(root,s);
return res;
}
- 404.左叶子之和:使用后序遍历。特殊判断是否存在左叶子结点。
cpp
int dfs(TreeNode* root){
if(!root)return 0;
int value=0;
if(root->left){
if(!root->left->left&&!root->left->right){
value+=root->left->val;
}
}
return value+dfs(root->left)+dfs(root->right);
}
int sumOfLeftLeaves(TreeNode* root) {
return dfs(root);
}
- 513.找树左下角的值:设置全局变量,然后dfs即可。
cpp
int ans=0;
int max_depth=0;
void dfs(TreeNode* root,int depth){
if(!root)return;
if(!root->left&&!root->right){
if(depth>max_depth){
max_depth=depth;
ans=root->val;
}
}
dfs(root->left,depth+1);
dfs(root->right,depth+1);
}
int findBottomLeftValue(TreeNode* root) {
dfs(root,1);
return ans;
}
- 112. 路径总和:后序遍历。
cpp
bool dfs(TreeNode* root,int sum,int targetSum){
if(!root->left&&!root->right){
if(sum==targetSum){
return true;
}
return false;
}
bool left=false,right=false;
if(root->left)left=dfs(root->left,sum+root->left->val,targetSum);
if(root->right)right=dfs(root->right,sum+root->right->val,targetSum);
return left||right;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(!root)return false;
return dfs(root,root->val,targetSum);
}
*106.从中序与后序遍历序列构造二叉树:一道好题,从前序遍历建立树的模板。首先理解中序+后序怎么构造二叉树,然后利用前序的方式显示的建立每一个结点TreeNode*node=new TreeNode()
。注意分割左右子树的数组时,迭代器是左闭右开[begin,end)
的!
cpp
TreeNode*dfs(vector<int>& inorder,vector<int>& postorder){
if(inorder.size()==0)return nullptr;
if(inorder.size()==1){
TreeNode*node=new TreeNode(inorder[0]);
return node;
}
int value=postorder[postorder.size()-1];
TreeNode*root=new TreeNode(value);
int idx=-1;
for(int i=0;i<inorder.size();i++){
if(inorder[i]==value){idx=i;break;}
}
vector<int>inorder_left(inorder.begin(),inorder.begin()+idx);
vector<int>inorder_right(inorder.begin()+idx+1,inorder.end());
vector<int>postorder_left(postorder.begin(),postorder.begin()+idx);
vector<int>postorder_right(postorder.begin()+idx,postorder.end()-1);
root->left=dfs(inorder_left,postorder_left);
root->right=dfs(inorder_right,postorder_right);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return dfs(inorder,postorder);
}