递归判断两个树是否相等
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == nullptr && q == nullptr)
return true;
else if (p == nullptr || q == nullptr)
return false;
else if (p->val != q->val)
return false;
else
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
};
递归判断左右子树是否对称,用else覆盖所有情况
bool isSymmetric(TreeNode* root) {
if (root==NULL) return true;
return dfs(root->left,root->right);
}
//必须新写一个递归,递归判断左左和右右,左右和右左
bool dfs(TreeNode* left,TreeNode* right) {
if(left==NULL&&right==NULL) return true;
else if (left==NULL||right==NULL) return false;
else if(left->val!=right->val) return false;
else return dfs(left->left,right->right)&&dfs(left->right,right->left);
}
在外面记录一个当前最大深度,找到叶子节点时判断是否大于最大深度,若大于则更新,最后返回最大深度
class Solution {
public:
int ans;
int maxDepth(TreeNode* root) {
ans=0;
dfs(root,0);
return ans;
}
void dfs(TreeNode* node,int depth)
{
if(node==nullptr){
if(depth>ans)
ans=depth;
return;
}
dfs(node->left,depth+1);
dfs(node->right,depth+1);
}
};
简介版答案
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
1、根据前序遍历查找根节点,根据中序遍历查找该节点,得到其左右范围,构造该节点并递归遍历
2、递归函数设置当前查找范围,前序中序数组和当前根节点序号设置为全局变量保存
class Solution {
public:
vector<int> pre,ino;
int temp=0;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
pre=preorder;ino=inorder;
//不能传入preorder.size()-1,不然少输出一个数
return dfs(0,preorder.size());
}
//递归没有必要传入vector,设置成为成员变量
TreeNode* dfs(int a,int b)
{
//前序遍历指针没有必要传入函数,设置一个成员变量进行记录,如果到头则返回
if(temp==pre.size()||a==b) return NULL;
TreeNode* res=NULL;
for(int i=a;i<b;i++)
if(ino[i]==pre[temp]){
res=new TreeNode(pre[temp++]);
res->left=dfs(a,i);
res->right=dfs(i+1,b);
break;
}
return res;
}
};
class Solution {
int post_idx;
unordered_map<int, int> idx_map;
public:
TreeNode* helper(int in_left, int in_right, vector<int>& inorder, vector<int>& postorder){
// 如果这里没有节点构造二叉树了,就结束
if (in_left > in_right)
return nullptr;
// 选择 post_idx 位置的元素作为当前子树根节点
int root_val = postorder[post_idx];
TreeNode* root = new TreeNode(root_val);
// 根据 root 所在位置分成左右两棵子树
int index = idx_map[root_val];
// 下标减一
post_idx--;
// 构造右子树
root->right = helper(index + 1, in_right, inorder, postorder);
// 构造左子树
root->left = helper(in_left, index - 1, inorder, postorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// 从后序遍历的最后一个元素开始
post_idx = (int)postorder.size() - 1;
// 建立(元素,下标)键值对的哈希表
int idx = 0;
for (auto& val : inorder)
idx_map[val] = idx++;
return helper(0, (int)inorder.size() - 1, inorder, postorder);
}
};
参考113的解析,不用存路径序列,递归代码简单
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if (root == nullptr) {
return false;
}
if (root->left == nullptr && root->right == nullptr) {
return sum == root->val;
}
return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
}
};
1、题目要求的是从根节点到叶子节点的路径序列,所以每个节点必须塞入临时数组,不存在不塞的情况
2、如果和正好相等,并且左右子节点都为空,才是符合要求的序列
3、临时数组作为参数传入,不用考虑弹出操作
class Solution {
public:
vector<vector<int>> ans;
int m_sum;
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<int> temp;
int count=0,m_sum=sum;
dfs(root,temp,count);
return ans;
}
void dfs(TreeNode* root,vector<int> temp,int count)
{
if(root==NULL) return;
count+=root->val;
temp.push_back(root->val);
if(count==m_sum&&root->left==NULL&&root->right==NULL){
ans.push_back(temp);
return;
}
//有负数样例,不能用大小取判断
else{
dfs(root->left,temp,count);
dfs(root->right,temp,count);
return;
}
}
};
一边加一边深搜,父节点乘以10加上子节点
class Solution {
public:
int dfs(TreeNode* root, int prevSum) {
if (root == nullptr)
return 0;
int sum = prevSum * 10 + root->val;
if (root->left == nullptr && root->right == nullptr)
return sum;
else
return dfs(root->left, sum) + dfs(root->right, sum);
}
int sumNumbers(TreeNode* root) {
return dfs(root, 0);
}
};
1、当前节点最大值=该节点+左右子节点之和,负数不加,因为路径可以两条。
2、返回值为当前节点+左右子节点较大者,负数不加,因为路径只能一条。
class Solution {
private:
int maxSum = INT_MIN;
public:
int maxGain(TreeNode* node) {
if (node == nullptr) {
return 0;
// 递归计算左右子节点的最大贡献值,只有在最大贡献值大于 0 时,才会选取对应子节点
int leftGain = max(maxGain(node->left), 0);
int rightGain = max(maxGain(node->right), 0);
// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值之和
int priceNewpath = node->val + leftGain + rightGain;
// 更新答案
maxSum = max(maxSum, priceNewpath);
// 返回节点的最大贡献值
return node->val + max(leftGain, rightGain);
}
int maxPathSum(TreeNode* root) {
maxGain(root);
return maxSum;
}
};
深度优先搜索,用depth记录当前深度,depth不能设置为全局,应该设置为参数,ans设置为全局记录右视图
按照中->右->左的方式递归,如果当前节点为该层第一个则记录为右视图
class Solution {
public:
vector<int> ans;
vector<int> rightSideView(TreeNode* root) {
dfs(root,0);
return ans;
}
void dfs(TreeNode* node,int depth){
if(node==nullptr) return;
if(depth==ans.size())
ans.push_back(node->val);
depth++;
dfs(node->right,depth);
dfs(node->left,depth);
}
};
TreeNode* invertTree(TreeNode* root) {
//镜像等于交换左右子树
if(root==NULL) return NULL;
swap(root->left,root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
解法1: 中序遍历存储到数组,取nodes[k - 1]
解法2: 直接count中序遍历过的元素,到k个的时候退出
解法3: 二分搜索,根据BST的性质,如果左子树的nodes数目多于k个,直接去左子树递归查找,如果左子树恰好为k-1个,返回根的val,如果左子树节点数L小与k-1,去右子树中查找第k - L - 1小的元素。
class Solution {
public:
//递归逆中序遍历,并输出第k-1个
vector<int> ans;
int kthLargest(TreeNode* root, int k) {
middle(root);
return ans[k-1];
}
void middle(TreeNode* root)
{
if(root==NULL) return;
else{
middle(root->right);
ans.push_back(root->val);
middle(root->left);
}
}
};
1、如果左右子树都true,或自己为true,左右子树只有一个true,则该节点是唯一最近祖先
2、只要自己或左右子树有一个是true,就返回true
class Solution {
public:
int p1,q1;
TreeNode* ans;
bool dfs(TreeNode* root)
{
if(root==NULL) return false;
int left=dfs(root->left);
int right=dfs(root->right);
if ((left&&right)||((left||right)&&(root->val==p1||root->val==q1))) ans=root;
return (root->val==p1||root->val==q1||left||right);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
p1=p->val;
q1=q->val;
dfs(root);
return ans;
}
};
根据二叉搜索树的性质
1、如果目标节点大于当前节点值,则去右子树中删除;
2、如果目标节点小于当前节点值,则去左子树中删除;
3、如果目标节点就是当前节点,分为以下三种情况:
a、其无左子:其右子顶替其位置,删除了该节点;
b、其无右子:其左子顶替其位置,删除了该节点;
c、其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。
TreeNode* deleteNode(TreeNode* root, int key)
{
if (root == nullptr) return nullptr;
if (key > root->val) root->right = deleteNode(root->right, key); // 去右子树删除
else if (key < root->val) root->left = deleteNode(root->left, key); // 去左子树删除
else // 当前节点就是要删除的节点 {
if (! root->left) return root->right; // 情况1,欲删除节点无左子
if (! root->right) return root->left; // 情况2,欲删除节点无右子
TreeNode* node = root->right; // 情况3,欲删除节点左右子都有
while (node->left) // 寻找欲删除节点右子树的最左节点
node = node->left;
node->left = root->left; // 将欲删除节点的左子树成为其右子树的最左节点的左子树
root = root->right; // 欲删除节点的右子顶替其位置,节点被删除
}
return root;
}
二叉树的直径等于每个节点长度的最大值,这个长度是左右子树加自己,用一个成员变量记录直径
class Solution {
int ans;
int depth(TreeNode* rt){
if (rt == NULL)
return 0; // 访问到空节点了,返回0
int L = depth(rt->left); // 左儿子为根的子树的深度
int R = depth(rt->right); // 右儿子为根的子树的深度
ans = max(ans, L + R + 1); // 计算d_node即L+R+1 并更新ans
return max(L, R) + 1; // 返回该节点为根的子树的深度
}
public:
int diameterOfBinaryTree(TreeNode* root) {
ans = 1;
depth(root);
return ans - 1;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/diameter-of-binary-tree/solution/er-cha-shu-de-zhi-jing-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1、使用广搜,方便查找每层的最大宽度,由于中间可能有空节点,最大宽度不等于每层个数,而等于首尾序号差
2、防止序号溢出,下一层序号要减去当前层的起始值
int widthOfBinaryTree(TreeNode* root) {
if (root == nullptr)
return 0;
int res = 0;
queue<TreeNode*> q;
root->val = 0;
q.push(root);
while (!q.empty()) {
res = max(res, q.back()->val - q.front()->val + 1);
int offset = q.front()->val;
int n = q.size();
for (int i = 0; i < n; ++i) {
TreeNode* curr = q.front();
q.pop();
curr->val -= offset;
if (curr->left){
curr->left->val = curr->val*2;
q.push(curr->left);
}
if (curr->right){
curr->right->val = curr->val*2+1;
q.push(curr->right);
}
}
}
return res;
}