【牛客剑指offer】数据结构——树——简单
JZ55 二叉树的深度
代码
/*
int TreeDepth(TreeNode* pRoot) {
if(pRoot==NULL){
return 0;
}
int lDeep=TreeDepth(pRoot->left);
int rDeep=TreeDepth(pRoot->right);
return max(lDeep+1,rDeep+1);
}
get
思路:
递归
树的深度=左右子树深度的较大值+1
沿着树的左右节点向下遍历,直至空节点时,空节点的深度为0
JZ27 二叉树的镜像
代码
TreeNode* Mirror(TreeNode* pRoot) {
// write code here
if(pRoot==nullptr){
return nullptr;
}
TreeNode* lchild=Mirror(pRoot->left);
TreeNode* rchild=Mirror(pRoot->right);
pRoot->left=rchild;
pRoot->right=lchild;
return pRoot;
}
get
思路:
递归遍历左右子树、左右孩子节点
遍历到最底层的空节点时,返回空
递归处理左右子树,并保存左右子节点,用于后续交换左右孩子
交换左右孩子完成镜像
JZ32从上往下打印二叉树
代码
vector<int> PrintFromTopToBottom(TreeNode* root) {
vector<int> res;
if(root==nullptr){
return res;
}
queue<TreeNode*> q; //借助队列实现层次遍历
q.push(root); //根入队列
TreeNode* cur;
while(!q.empty()){ //队列非空,处理队首元素
cur=q.front();
q.pop();
res.push_back(cur->val); //队首元素的值纳入结果数组
if(cur->left!=nullptr){ //有左右孩子,孩子入队
q.push(cur->left);
}
if(cur->right!=nullptr){
q.push(cur->right);
}
}
return res;
}
get
二叉树为空时,直接返回空的结果——注意返回类型
有题目可得要使用层序遍历。往往通过队列来实现层序遍历。
初始化队列:根节点入队。
当队列不空时,进行层序遍历。处理队首元素,将其val值纳入结果数组,并弹出队首元素。
若队首节点有左右孩子,则左右孩子纳入队列,待后续处理。
JZ82二叉树中和为某一值的路径
代码
bool hasPathSum(TreeNode* root, int sum) {
// write code here
if(root== NULL){
return false;
}
if(root->left==NULL && root->right==NULL && sum==root->val){
return true;
}
return (hasPathSum(root->right, sum-root->val) ||
hasPathSum(root->left, sum-root->val));
}
get
判断路径为某一值——每次经过路径中的一层节点,目标值减去当前节点的val,在当前节点的子树中寻找 // 子树路径值= =结果 // 的路径。
由此可使用递归的方法处理。
当处理到空节点时,返回false。
当处理到叶子节点,且当前sum= = 当前val时,表示这样的路径是存在的,返回true。
若上述两情况均不满足,递归处理当前节点的左右子树。
在处理子树时,目标sum为当前sum减去当前节点的val,只需在子树中找到路径为结果值的路径即可。
JZ79判断是不是平衡二叉树
代码
int deep(TreeNode* root) {
if (root == NULL) {
return 0;
}
int left = deep(root->left);
int right = deep(root->right);
return max(left + 1, right + 1);
}
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot == NULL){
return true;
}
int left = deep(pRoot->left);
int right = deep(pRoot->right);
if(abs(left-right)>1){
return false;
}
return (IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right));
}
get
思路:
获取树的深度的函数deep()
判断树是不是二叉树,所有结点的左右子树深度相差为0或1.
空节点左右子树高度均为0,是平衡二叉树。
非空节点,获取左右子树的高度,若高度差绝对值大于1,则不是平衡二叉树。
若满足左右子树高度差为0或1,则继续判断子树是否满足平衡二叉树,若左右子树均为平衡二叉树,且左右子树的高度差为0或1,则该节点为根节点的树为平衡二叉树。
——在判断左右子树是否为平衡二叉树中,用到了递归处理。
JZ28对称的二叉树
代码
//判断是否为镜像的子树
bool isMirror(TreeNode* root1, TreeNode* root2){
//都为空,镜像
if(root1==NULL && root2==NULL){
return true;
}
//只有一个节点为空。或两节点的val不同
if((root1==NULL&&root2!=NULL) || (root1!=NULL&&root2==NULL)
||(root1->val!=root2->val)){
return false;
}
//当前根节点满足镜像,处理其子树
return (isMirror(root1->left,root2->right)&&isMirror(root1->right,root2->left));
}
bool isSymmetrical(TreeNode* pRoot) {
return isMirror(pRoot,pRoot);
}
get
联系镜像二叉树。
镜像的二叉树,两棵树左右对称。 某节点的左子树与对称位置的右子树镜像。
对称的二叉树,根节点的左右子树镜像。
参考up 香辣鸡排蛋包饭 的图示:
问题可推演为,判断一棵树是否沿根节点镜像。
镜像——树A的左侧与树B的右侧镜像、对称。
一棵树对称——左右子树镜像——同一棵树的左侧与右侧镜像。
判断镜像的函数的两个参数均为根节点即可。
判断镜像:
空树,镜像。
只有一个为空树,或当前处理的树的两个根节点val值不同,不镜像。
两者均非空,且val值相同,继续处理其子树。
判断镜像,对子树的处理为 树A的左侧与树B的右侧。树A的右侧与树B的左侧。
JZ68二叉搜索树的最近公共祖先
代码
int lowestCommonAncestor(TreeNode* root, int p, int q) {
// write code here
while (root) {
if (root->val < p && root-> val < q) {
root = root->right;
}
else if (root->val > p && root-> val > q) {
root = root->left;
}
else{
return root->val;
}
}
return -1;
}
get
思路:
讲解视频
二叉搜索树有序
当p、q均大于或均小于root时,两者在root的同一侧,则root可下移到对应侧的孩子节点,继续判断。
当p、q一大一小时,两者在root的两侧,则root即为其最近公共祖先