前言
又是学习LeetCode二叉树的新一天,今天还是接着学习一下二叉搜索树的内容,希望博主记录的内容能够对大家有所帮助 ,一起加油吧朋友们!💪💪💪
二叉搜索树中的众数
LeetCode题目链接
给一个含重复值的二叉搜索树的根节点root,返回该树的所有众数(以数组格式)

思路梳理:这道题其实也是可以利用二叉搜素数中序遍历节点值递增的规律来写,因为就是可以在递归遍历的时候去更新当前节点频率和最大节点频率来完成这样,当当前节点频率大于等于最大节点频率时就把当前节点的值加入到一个整数列表中🤔🤔🤔
我们接下来梳理递归三要素
1 2
| private void inOrderTraversal(TreeNode root){}
|
1 2
| if(root == null) return;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| inOrderTraversal(root.left);
if(root.val == preVal){ curCount++; }else{ curCount = 1; }
if(curCount > maxCount){ maxCount = curCount; result.clear(); result.add(root.val); } else if(curCount == maxCount){ result.add(root.val); } preVal = root.val;
inOrderTraversal(root.right);
|
完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Solution { private int maxCount = 0; private int curCount = 0; private int preVal = Integer.MIN_VALUE; private List<Integer> result = new ArrayList<>(); public int[] findMode(TreeNode root) { inOrderTraversal(root); return result.stream().mapToInt(Integer::intValue).toArray(); }
private void inOrderTraversal(TreeNode root){ if(root == null) return;
inOrderTraversal(root.left);
if(root.val == preVal){ curCount++; }else{ curCount = 1; }
if(curCount > maxCount){ maxCount = curCount; result.clear(); result.add(root.val); } else if(curCount == maxCount){ result.add(root.val); } preVal = root.val;
inOrderTraversal(root.right); } }
|
这里可以提一下的是最后将列表转换成整型数组的一步操作
1
| return result.stream().mapToInt(Integer::intValue).toArray();
|
.stream()是java 8引入的Stream API中的一个方法,用于从集合( 如 List、Set、Map 等)或数组生成一个流(Stream)🤔
1 2 3 4
| List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .filter(name -> name.startsWith("A")) .forEach(System.out::println);
|
mapToInt() 是 Java Stream API 提供的用于将流中的对象映射为基本类型的方法,类似的方法还有mapToDouble()和mapToLong()等。
1 2 3 4 5
| List<Integer> numbers = Arrays.asList(1, 2, 3, 4); int[] result = numbers.stream() .mapToInt(Integer::intValue) .toArray();
|
intValue() 是 Integer 类的一个方法,它的作用是将 Integer 对象转换为基本数据类型 int。在 Java 中,包装类(如 Integer、Double 等)都有类似的转换方法,将包装类的对象转换为对应的基本数据类型。
1 2 3
| result.stream().mapToInt(Integer::intValue).toArray(); result.stream().mapToDouble(Double::doubleValue).toArray(); result.stream().mapToLong(Long::longValue).toArray();
|
我们也来梳理一下迭代法
- 主要就是中序遍历需要先把root节点压栈,然后把左子树节点递归入栈,然后弹出root节点进行处理,处理完后递归处理右节点,处理的逻辑和递归一样,然后的话就是栈一开始为空,循环条件加上一个当前节点不为空,而当前节点初始化为root🤔🤔🤔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { public int[] findMode(TreeNode root) { int maxCount = 0; int curCount = 0; int preVal = Integer.MIN_VALUE; List<Integer> result = new ArrayList<>(); Stack<TreeNode> stack = new Stack<>(); TreeNode cur = root; while(cur != null || !stack.isEmpty()){ if(cur != null){ stack.push(cur); cur = cur.left; }else{ cur = stack.pop(); if(cur.val == preVal){ curCount++; }else{ curCount = 1; }
if(curCount > maxCount){ maxCount = curCount; result.clear(); result.add(cur.val); }else if(curCount == maxCount){ result.add(cur.val); } preVal = cur.val; cur = cur.right; } } return result.stream().mapToInt(Integer::intValue).toArray(); }
}
|
二叉树的最近公共祖先
LeetCode题目链接
给定一个二叉树,找到该树中两个指定节点的最近公共祖先

我们来进行思路梳理🤔🤔🤔
- 首先的话就是找最近公共祖先我们需要从底向上遍历二叉树,所以只能通过后序遍历(左右中)来实现从底向上遍历🤔🤔🤔
1 2 3 4 5 6
| 递归函数返回值 递归函数(递归参数给定节点p,递归参数给定节点q,递归参数二叉树根节点root){ //递归出口 //处理左子树 //处理右子树 //处理中间父结点 }
|
- 接着的话最重要的就是怎么判断中间父结点是不是给定节点p和q的最近公共祖先呢🤔🤔🤔,如果左子树与右子树分别找到q/p则当前root就是最近的公共祖先

- 那有人会说了如果root是q/p呢,这个就属于递归出口的判断逻辑了,首先我们会判断每个节点也必然会进行空节点判断所以递归出口有
if(root == null)return null;,如果root为q/p那么也得返回找到的root节点然后呢?🤔🤔🤔接着往其左右子树去找剩下的节点能不能找到
1 2 3 4 5 6
| TreeNode 递归函数(递归参数给定节点p,递归参数给定节点q,递归参数二叉树根节点root){ if(root == q || root == p || root == null) return root; }
|
思路梳理完毕后我们来紧接着梳理递归三要素🤔🤔🤔
1
| public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {}
|
1
| if(root == q || root == p || root == null) return root;
|
1 2 3 4 5 6
| TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if(left != null && right != null) return root; if(left == null) return right; return left;
|
递归法java代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == q || root == p || root == null) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if(left != null && right != null) return root; if(left == null) return right; return left; } }
|
我们接着来梳理迭代法的思路🤔🤔🤔
- 我们可以利用栈进行深度优先搜索来遍历二叉树,同时记录每个节点的父结点信息以便在找到p/q节点时能够追溯路径🤔🤔🤔
1
| HashMap<TreeNode,TreeNode> parentMap = new HashMap<>();
|
- 找到p和q节点时遍历其中一个节点的路径,返回第一个相交的节点作为最近公共祖先🤔🤔🤔
1 2 3 4 5 6 7 8 9 10 11
| HashSet<TreeNode> ancestors = new HashSet<>(); while(p != null){ ancestors.add(p); p = parentMap.get(p); }
while(!ancestors.contains(q)){ q = parentMap.get(q); }
return q;
|
完整迭代法代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null) return null; HashMap<TreeNode,TreeNode> parentMap = new HashMap<>(); Stack<TreeNode> stack = new Stack<>(); stack.push(root); parentMap.put(root, null);
while(!parentMap.containsKey(q) || !parentMap.containsKey(p)){ TreeNode cur = stack.pop();
if(cur.left != null){ parentMap.put(cur.left, cur); stack.push(cur.left); }
if(cur.right != null){ parentMap.put(cur.right, cur); stack.push(cur.right); } }
HashSet<TreeNode> ancestors = new HashSet<>(); while(p != null){ ancestors.add(p); p = parentMap.get(p); }
while(!ancestors.contains(q)){ q = parentMap.get(q); }
return q; }
|
二叉搜索树的最近公共祖先
LeetCode题目链接
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先

我们来进行思路梳理🤔🤔🤔
首先的话就是找最近公共祖先我们需要从底向上遍历二叉树,所以只能通过后序遍历(左右中)来实现从底向上遍历,这个逻辑不变🤔🤔🤔
接着的话最重要的就是怎么判断中间父结点是不是给定节点p和q的最近公共祖先呢🤔🤔🤔,如果左子树与右子树分别找到q/p则当前root就是最近的公共祖先,对于二叉搜索树的话,根节点的值大于左子树的值小于右子树的值,所以我们可以得到要找的最近公共祖先就是数组在[q.val, p.val]或者[p.val, q.val]之中
ok,我们直接梳理递归三要素
1
| public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {}
|
1
| if(root == null) return root;
|
1 2 3 4 5 6 7
| if(root.val > q.val && root.val > p.val){ return lowestCommonAncestor(root.left, p, q); } else if(root.val < q.val && root.val < p.val){ return lowestCommonAncestor(root.right, p, q); }else{ return root; }
|
总的递归代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| /**递归法 */ class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null) return root; if(root.val > q.val && root.val > p.val){ return lowestCommonAncestor(root.left, p, q);//往左找 } else if(root.val < q.val && root.val < p.val){ return lowestCommonAncestor(root.right, p, q);//往左找 }else{ return root;//找到了 } } }
|
我们接着来梳理迭代法的逻辑🤔🤔🤔
- 由于二叉搜索树的性质,我们递归本质上是去找一个数值介于p与q数值之间的节点,所以我们迭代法无需栈或者队列来存储节点🤔🤔🤔
迭代法代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { while(root != null){ if(root.val > q.val && root.val > p.val) { root = root.left; }else if(root.val < q.val && root.val < p.val){ root = root.right; }else{ return root; } } return null; } }
|
总结
国庆假期结束,开始加油啦✊✊✊