上一篇文章:【力扣刷题】Day19——二叉树专题_塔塔开!!!的博客-CSDN博客
题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
思路:这题根验证二叉搜索树得第二种写法如出一辙,这不过本题他就是一棵二叉搜索树,其中序遍历是有序的,我们利用这一性质,使用pre(相当于一个指针)
记录当前节点的前一个节点,每次在根处进行判断即可。
Code
class Solution {
int pre = -1;// 用作于指针
int res = 0x3f3f3f3f;
public int getMinimumDifference(TreeNode root) {
dfs(root);
return res;
}
public void dfs(TreeNode root){
if(root == null){
return ;
}
// 左
dfs(root.left);
if(pre == -1){
pre = root.val;
}else {
res = Math.min(res, Math.abs(root.val - pre));
pre = root.val;
}
// 右
dfs(root.right);
}
}
题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)
Code
思路一:哈希表计数(普通二叉树的求法)
自己写的还是太繁琐了,hhhhh…
/**
可以用一个哈希表来计数, 找到出现次数最多的所有数
*/
class Solution {
Map<Integer, Integer> mp = new HashMap<>();
public int[] findMode(TreeNode root) {
dfs(root);
int max_cnt = 0;
for (Integer key : mp.keySet()) {
max_cnt = Math.max(max_cnt, mp.get(key));
}
List<Integer> list = new ArrayList<>();
for(Integer key : mp.keySet()){
if(mp.get(key) == max_cnt){
list.add(key);
}
}
int[] res = new int[list.size()];
for(int i = 0; i < list.size(); i ++) res[i] = list.get(i);
return res;
}
public void dfs(TreeNode root){
if(root == null){
return ;
}
dfs(root.left);
mp.put(root.val, mp.getOrDefault(root.val, 0) + 1);
dfs(root.right);
}
}
思路二:二叉搜索数的性质进行求解(双指针比较当前节点和前驱节点,计数, 更新等)
class Solution {
List<Integer> list = new ArrayList<>();
int pre = -1;
int cnt = 0;// 表示当前节点的值
int max_cnt = 0;// 最大出现次数
public int[] findMode(TreeNode root) {
dfs(root);
int[] res = new int[list.size()];
for(int i = 0; i < list.size(); i ++) res[i] = list.get(i);
return res;
}
public void dfs(TreeNode root){
if(root == null){
return ;
}
// 左
dfs(root.left);
// 根
if(pre == root.val){
cnt ++;
pre = root.val;
}else {// 新的节点
cnt = 1;
pre = root.val;
}
// 更新max_cnt
if(cnt == max_cnt){
// 如果cnt == max_cnt,就把当前节点加入到集合中
list.add(root.val);
}else if(cnt > max_cnt){
// (出现了更多的)
// 否则,当前节点的值重复量是最多的,直接把list清空,然后
// 把当前节点的值加入到集合中
max_cnt = cnt;
list.clear();
list.add(root.val);
}
// 右
dfs(root.right);
}
}
题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)
思路:dfs后序遍历,从低往上搜索公共祖先
Code
/**
由于是找找最近的,我们dfs的顺序采用 后序遍历(左右根,最后处理根),最终一定是最近的
本题的关键就在于,判断当前节点的左右子树是否包含 p q:
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return dfs(root, p, q);
}
// dfs函数:返回pq的最近公共祖先
// 如果以root为根的子树(左右子树)包含p和q,则返回最近公共祖先
// 如果...只包含 p,则返回q
// 如果...只包含 q,则返回p
// 如果都不包含,则返回NULL
public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
if(root == null || root == p || root == q){
return root;
}
// 判断左右子树是否包含 p q
// 左右
TreeNode left = dfs(root.left, p, q);
TreeNode right = dfs(root.right, p, q);
if(left == null) return right;// 左边不包含pq 那么最近..就在右边
if(right == null) return left;
// 左边和右边都不空(p q左右各一个 那么此时根节点就为最近公共祖先) // 根
return root;
}
}
题目链接:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
Code
用上一题的二叉树的最近公共祖先的代码完全可以过(二叉搜索树也是二叉树嘛!!)
/**
由于是找找最近的,我们dfs的顺序采用 后序遍历(左右根,最后处理根),最终一定是最近的
本题的关键就在于,判断当前节点的左右子树是否包含 p q:
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return dfs(root, p, q);
}
public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
if(root == null || root == p || root == q){
return root;
}
TreeNode left = dfs(root.left, p, q);
TreeNode right = dfs(root.right, p, q);
if(left == null) return right;
if(right == null) return left;
return root;
}
}
利用二叉搜索树的性质:左子树的值都比跟小,右子树的值都比根大,这样我们就可以确定搜索的方向了!
root
的值 比 q p
大,那么说明p q
的最近公共节点在左子树,我们遍历左子树即可root
的值 比 q p
小,那么说明p q
的最近公共节点在右子树,我们遍历左子树即可p q
各位于当前root
的左右子树,那么此时root
即为最近公共祖先跟上一题还是一样的思路,只不过我们明确了遍历的方向而已,关键依旧在于判断 左右子树是否包含
p和q
!
Code
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return dfs(root, p, q);
}
public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
if(root == null || root == p || root == q){
return root;
}
if(root.val > p.val && root.val > q.val) return dfs(root.left, p, q);
if(root.val < p.val && root.val < q.val) return dfs(root.right, p, q);
return root;
}
}
题目链接:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)
思路:利用二叉搜索树的性质,遍历找到该插入位置(空节点)即可
递归出口:当root
为空我们创建要插入的节点node
,然后return node
,最后会不断的回溯返回,直到根节点,最终递归完整结束返回根节点即可
当前root.val > val
,说明要往左子树进行插入操作
当前root.val < val
,说明要往右子树进行插入操作
Code
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
return dfs(root, val);
}
public TreeNode dfs(TreeNode root, int val){
if(root == null){// 递归出口,之后不断回溯返回,最终形成一棵树
TreeNode node = new TreeNode(val);
return node;
}
if(root.val > val) root.left = dfs(root.left, val);
if(root.val < val) root.right = dfs(root.right, val);
return root;
}
}
题目链接:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)
根据二叉搜索树的性质
Code
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
return dfs(root, key);
}
public TreeNode dfs(TreeNode root, int key){
if(root == null){
return null;
}
if(root.val > key) root.left = dfs(root.left, key);
else if(root.val < key) root.right = dfs(root.right, key);
else{// 当前节点是要删除的节点
if(root.left == null) return root.right;// 情况1:左子树为空
if(root.right == null) return root.left;// 情况2:右子树为空
// 情况3:左右都不为空
TreeNode node = root.right;
while(node.left != null){// 找出右子树最左的节点
node = node.left;
}
node.left = root.left;// 删除欲删除节点 拼接
root = root.right;// 跟换删除后树的根节点
}
// 递归完整结束后 返回根节点
return root;
}
}