530.二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点
root,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
530. 二叉搜索树的最小绝对差 - 力扣(Leetcode)
思路
给定一组数,任意两个数差值最小的情况出现在这组数中任意相邻的两个数中。
二叉搜索树按照中序遍历的结果是自然排序的。
在遍历过程中,记录相邻的两个节点pre和cur,当前节点为cur,其上一个遍历的节点为pre。
记录当前最小绝对差为minDifference,当cur.val - pre.val小于minDifference时,更新minDifference。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
TreeNode pre = null;
int minDifference = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
traversal(root);
return minDifference;
}
private void traversal(TreeNode cur){
if(cur == null){
return;
}
// 左
traversal(cur.left);
// 中
if(pre != null){
// 此处不用Math.abs()的原因:
// 二叉搜索树中 pre.val < cur.val
minDifference = Math.min(minDifference, cur.val - pre.val);
}
// 记录当前节点为下一次比较中的pre
pre = cur;
traversal(cur.right);
}
}
501.二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点
root,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。 如果树中有不止一个众数,可以按 任意顺序 返回。 假定 BST 满足如下定义:
- 结点左子树中所含节点的值 小于等于 当前节点的值
- 结点右子树中所含节点的值 大于等于 当前节点的值
- 左子树和右子树都是二叉搜索树
思路
- 遍历二叉树,使用哈希表
map记录每个节点数值及其出现的频数,同时在遍历过程中,不断更新最大频数maxFrequency。 - 遍历
map,找到所有频数为maxFrequency的键,保存到list中。 - 将
list转成数组,并返回。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 在遍历过程中统计最大的频率
int maxFrequency = 0;
public int[] findMode(TreeNode root) {
Map<Integer,Integer> map = new HashMap<>();
traversal(root, map);
// 遍历map
// 找出值为 maxFrequency 的键
List<Integer> list = new ArrayList<>();
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
if(entry.getValue() == maxFrequency){
list.add(entry.getKey());
}
}
return list.stream().mapToInt(o -> o).toArray();
}
private void traversal(TreeNode node,Map<Integer,Integer> map){
if(node == null){
return;
}
traversal(node.left, map);
int frequency = map.getOrDefault(node.val, 0) + 1;
maxFrequency = Math.max(maxFrequency, frequency);
map.put(node.val, frequency);
traversal(node.right, map);
}
}
236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
提示:
- 树中节点数目在范围
[2, 105]内。-109 <= Node.val <= 109- 所有
Node.val互不相同。p != qp和q均存在于给定的二叉树中。
236. 二叉树的最近公共祖先 - 力扣(Leetcode)
思路
思路1
遍历二叉树,在过程中,使用path记录当前路径。
使用hasBoth、hasP和hasQ分别记录找到一条同时含有p和q的路径、找到一条含有p的路径和找到一条含有q的路径的情况。
使用paths保存找到的路径。
- 当
hasBoth为true时,表示已经找到一条包含p和q的路径,之后所有的遍历直接跳过。 paths最终只包含 1项 或 2项 ,当且仅当找到一条同时含有p和q的路径时包含1项。- 对于叶子节点,
- 首先将该节点加入路径中,
- 如果当前路径中包含了
p和q两个节点,将paths清空,再将当前路径保存到paths中,并将hasBoth设置为true; - 否则,如果当前路径中包含了
p,且hasP为false,这意味着paths中尚未保存含有p的路径,将当前路径保存到paths中,并将hasP设置为true; - 同理,如果当前路径中包含了
q,且hasQ为false,这意味着paths中尚未保存含有q的路径,将当前路径保存到paths中,并将hasQ设置为true;
- 当遍历结束,判断
paths的大小。- 如果
paths中只有一个数据项,说明p和q在同一条路径上,遍历该路径,如果第一个遍历到p,意味着p是q的祖先(/父)节点,将p返回;同理,如果先遍历到q,则返回q; - 否则,
p和q不是直接祖孙关系,分别在两条路径中;- 先分别遍历两条路径,定位到这两个节点在路径中的位置;
- 从定位的下标向0下标回溯,找到最近的相同值,该元素就是
p和q的最近公共祖先的值。 - 通过该值在树中找到该节点,并返回。
- 如果
思路2
找祖先是自下而上遍历,即先搜索节点的子树,再搜索节点本身,符合该要求的遍历方式是后序遍历,遍历顺序是左右中。
对于二叉树的一个节点,
- 如果当前节点就是目标节点,或者是
null,直接返回当前节点。 - 如果它的左子树中找到一个目标节点,右子树中找到另一个目标节点,那么当前节点为这两个节点的公共祖先。
- 由于后序遍历先遍历子树,再遍历当前节点,所以两个节点的最近公共祖先节点较其他公共祖先节点先遍历到,因为最近公共祖先节点是其他公共祖先节点的子孙节点。
- 如果它的其中的一个子树中返回了节点,另一个子树没有找到目标,这就出现了两种情况
- 找到目标的子树中含有最近公共祖先,即当前节点的子树中同时含有两个目标节点,子树中返回的目标就是所求的最近公共祖先,因此返回这个结果即可;
- 找到目标的子树中只含有其中一个目标值,而另一棵子树中也未找到目标值,那么当前节点还不是最近公共祖先,最近公共祖先还在当前节点的祖先节点中,将找到的目标返回即可。
代码
思路1的代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
boolean hasBoth = false;
boolean hasP = false;
boolean hasQ = false;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
List<List<Integer>> paths = new ArrayList<>();
List<Integer> path = new ArrayList<>();
traversal(root, p, q, paths,path);
if(paths.size() == 1){
// 在同一条路径上
for(int i=0;i<paths.get(0).size();i++){
if(paths.get(0).get(i) == p.val){
return p;
}
if(paths.get(0).get(i) == q.val){
return q;
}
}
return null;
}
// 两条路径
int index1 = 0,index2 =0;
for(int i=0;i<paths.get(0).size();i++){
if(paths.get(0).get(i) == p.val || paths.get(0).get(i) == q.val){
index1 = i;
break;
}
}
for(int i=0;i<paths.get(1).size();i++){
if(paths.get(1).get(i) == p.val || paths.get(1).get(i) == q.val){
index2 = i;
break;
}
}
for(int i = index1; i>=0; i--){
for(int j = index2; j>=0; j--){
if(paths.get(0).get(i) == paths.get(1).get(j)){
return getNode(root, paths.get(0).get(i));
}
}
}
return null;
}
private void traversal(TreeNode node,TreeNode p, TreeNode q, List<List<Integer>> paths,List<Integer> path){
if(hasBoth){
return;
}
if(node.left == null && node.right == null){
path.add(node.val);
if(path.contains(p.val) && path.contains(q.val)){
hasBoth = true;
paths.clear();
paths.add(new ArrayList<Integer>(path));
}else if(path.contains(p.val) && hasP == false){
paths.add(new ArrayList<Integer>(path));
hasP = true;
}else if(path.contains(q.val) && hasQ == false){
paths.add(new ArrayList<Integer>(path));
hasQ = true;
}
path.remove(path.size() -1);
return;
}
// 中
path.add(node.val);
// 左
if(node.left != null){
traversal(node.left, p,q,paths,path);
}
// 右
if(node.right != null){
traversal(node.right,p, q, paths, path);
}
// 回退
path.remove(path.size() - 1);
}
private TreeNode getNode(TreeNode node,Integer num){
if(node == null){
return null;
}
if(node.val == num){
return node;
}
TreeNode left = getNode(node.left,num);
TreeNode right = getNode(node.right, num);
return left == null? right : left;
}
}
思路2的代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == p || root == q || 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;
}
// 至多一侧有节点
return left == null ? right : left;
}
}