今天把随想录的二叉树部分刷完了第一遍。
1. 二叉搜索树的最小绝对差
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
直接对比父节点与两子节点的差找出最小值,但此法不可行,还是放到数组中去遍历。
答案给出了遍历树的写法,用一个指针记录前一个结点,在取最小差值时,是对比前一个结点和当前节点的差值,而非父子结点间差值,显然这样的思路是合理的。
代码
class Solution {
private:
void inorder(TreeNode* root,vector<int>& nums) {
if (root==nullptr) return;
inorder(root->left,nums);
nums.push_back(root->val);
inorder(root->right,nums);
}
public:
int getMinimumDifference(TreeNode* root) {
vector<int> nums;
inorder(root,nums);
int ans=INT_MAX;
for (int i=1;i<nums.size();++i) {
ans=min(ans,nums[i]-nums[i-1]);
}
return ans;
}
};
2. 二叉搜索树中的众数
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
遍历一遍树,记录元素频数;遍历map,找到最大频数;遍历map,将频数等于最大频数的元素加入ans。
对于搜索树,可以利用其性质,相同元素必然相邻,用一个变量统计当前元素次数,如果等于maxCnt,就加入结果数组。当遇到大于maxCnt的计数,应当把结果集清空,重新加入当前元素,这样可以达到常数空间。
代码
class Solution {
private:
map<int,int> mp;
void dfs(TreeNode* root) {
if (!root) return;
mp[root->val]++;
dfs(root->left);
dfs(root->right);
}
public:
vector<int> findMode(TreeNode* root) {
mp.clear();
int maxFreq=INT_MIN;
dfs(root);
for (auto& elem:mp) maxFreq=max(maxFreq,elem.second);
vector<int> ans;
for (auto& elem:mp) if (elem.second==maxFreq) ans.push_back(elem.first);
return ans;
}
};
常数空间版:
class Solution {
private:
TreeNode* pre;
vector<int> ans;
int cnt=0;
int maxCnt=0;
void dfs(TreeNode* root) {
if (!root) return;
dfs(root->left);
if (!pre) {
cnt=1;
maxCnt=1;
ans.push_back(root->val);
} else {
if (root->val==pre->val) {
++cnt;
if (cnt>maxCnt) {
ans.clear();
maxCnt=cnt;
}
} else cnt=1;
if (cnt==maxCnt) ans.push_back(root->val);
}
pre=root;
dfs(root->right);
}
public:
vector<int> findMode(TreeNode* root) {
ans.clear();
pre=nullptr;
cnt=0;
maxCnt=0;
dfs(root);
return ans;
}
};
3. 二叉树的最近公共祖先
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
要找祖先节点,需要从下到上遍历,或者说需要回溯。而对于二叉树来说,后序遍历就是天然的回溯。
看到二叉树相关题目,首先就应该想到能不能遍历,用什么顺序遍历;不能遍历就想能不能放到数组里做。
代码
class Solution {
private:
TreeNode* ans;
bool postorder(TreeNode* root,TreeNode* p,TreeNode* q) {
if (!root) return false;
bool left=postorder(root->left,p,q);
bool right=postorder(root->right,p,q);
if ((left&&right)||((root==p||root==q)&&(left||right))) {
ans=root;
return false;
}
if (root==p||root==q||left||right) return true;
return false;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
ans=nullptr;
postorder(root,p,q);
return ans;
}
};
4. 二叉搜索树的最近公共祖先
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
利用搜索树的性质,自顶向下遍历,遇到的第一个在pq之间的结点,即为所求。
代码
class Solution {
private:
TreeNode* ans;
void dfs(TreeNode* root,int& p,int& q) {
if (root==nullptr) return;
if (root->val>=p&&root->val<=q) {
ans=root;
return;
}
else if (root->val<p) dfs(root->right,p,q);
else dfs(root->left,p,q);
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
ans=nullptr;
int low=min(p->val,q->val);
int high=max(p->val,q->val);
dfs(root,low,high);
return ans;
}
};
5. 二叉搜索树中的插入操作
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
只是要求插入二叉搜索树,而非平衡二叉搜索树,所以较为简单。
如果是平衡树,在插入后还需要做调平操作。如果不考虑时间复杂度,甚至可以把原有平衡二叉树还原成数组,插入新元素后再从数组重新构造二叉树。
代码
class Solution {
private:
void insert(TreeNode* root,int& val) {
if (val<root->val) {
if (!root->left) {
TreeNode* left=new TreeNode(val);
root->left=left;
return;
} else insert(root->left,val);
} else {
if (!root->right) {
TreeNode* right=new TreeNode(val);
root->right=right;
return;
} else insert(root->right,val);
}
}
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (!root) {
TreeNode* ans=new TreeNode(val);
return ans;
}
insert(root,val);
return root;
}
};
6. 删除二叉搜索树中的节点
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
辅助函数跟主函数名字有点相似,调用的时候不小心掉用了自己,我说怎么一直死循环……改完就好了。
采用返回结点的递归方式,更方便一些。先写个辅助函数,用于将结点插入到树中。删除时,如果当前结点值不等于目标值,根据大小关系递归调用左子结点或右子结点。如果相等,分情况讨论,没有孩子,则直接返回空指针;有一个孩子,则返回那个孩子;如果两个都存在,用辅助函数把左孩子插到右孩子上去,再返回右孩子即可。
随想录在孩子插入孩子的过程中是直接找右孩子的最左空结点,也是一样的,但我这个辅助函数更通用一些。
代码
class Solution {
private:
TreeNode* insert(TreeNode* root,TreeNode* child) {
if (!root) return child;
if (root->val<child->val) root->right=insert(root->right,child);
else root->left=insert(root->left,child);
return root;
}
TreeNode* delNode(TreeNode* root, int& key) {
if (!root) return root;
if (root->val==key) {
if (!root->left&&!root->right) return nullptr;
else if (!root->left&&root->right) return root->right;
else if (root->left&&!root->right) return root->left;
else {
root->right=insert(root->right,root->left);
return root->right;
}
} else if (root->val<key) {
root->right=delNode(root->right,key);
} else {
root->left=delNode(root->left,key);
}
return root;
}
public:
TreeNode* deleteNode(TreeNode* root, int key) {
return delNode(root,key);
}
};
7. 修剪二叉搜索树
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
初看比较复杂。但实际上情况也有限,依然使用返回结点的递归。
- 如果当前节点在范围内(左闭右闭),递归调用修剪左右孩子。
- 如果结点值小于下界,则其左孩子肯定不要了,递归修剪其右孩子并返回。
- 如果结点值大于上界,则其右孩子肯定不要了,递归修剪其左孩子并返回。
代码
class Solution {
private:
TreeNode* trim(TreeNode* root, int low, int high) {
if (!root) return root;
if (root->val>=low&&root->val<=high) {
root->left=trim(root->left,low,high);
root->right=trim(root->right,low,high);
return root;
} else if (root->val<low) {
return trim(root->right,low,high);
} else return trim(root->left,low,high);
}
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
return trim(root,low,high);
}
};
8. 将有序数组转换为二叉搜索树
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
每次将当前区间中间元素作为根节点即可,并递归调用左区间作为左子树,右区间作为右子树。
代码
class Solution {
private:
TreeNode* dfs(const vector<int>& nums,int low,int high) {
TreeNode* root;
if (low>high) root= nullptr;
else if (low==high) {
root=new TreeNode(nums[low]);
} else {
int mid=low+(high-low)/2;
root=new TreeNode(nums[mid]);
root->left=dfs(nums,low,mid-1);
root->right=dfs(nums,mid+1,high);
}
return root;
}
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return dfs(nums,0,nums.size()-1);
}
};
9. 把二叉搜索树转换为累加树
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
两种做法,一个是中序遍历把结点全都放到数组中,从后向前累加,需要n的额外空间。
第二个是中序遍历(左右互换),另设一个指针pre(初始化成值为零的结点),用于记录前一个结点,依次累加即可,只需要常数空间。
代码
方法一:
class Solution {
private:
void inorder(TreeNode* root,vector<TreeNode*>& tree) {
if (!root) return;
inorder(root->left,tree);
tree.push_back(root);
inorder(root->right,tree);
}
public:
TreeNode* convertBST(TreeNode* root) {
vector<TreeNode*> tree;
inorder(root,tree);
for (int i=tree.size()-2;i>=0;--i) tree[i]->val+=tree[i+1]->val;
return root;
}
};
方法二:
class Solution {
private:
TreeNode* pre;
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->right);
root->val+=pre->val;
pre=root;
inorder(root->left);
}
public:
TreeNode* convertBST(TreeNode* root) {
pre=new TreeNode(0); //可以再初始化一个指针,用于保存一开始的pre,最后delete
inorder(root);
return root;
}
};
Comments NOTHING