代码随想录Day21 - 二叉树
530. 二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值,而二叉搜索树是有序的。二叉搜索树采用中序遍历,其实就是一个有序数组(题目等同于在一个有序数组中找两个数最小差值)。
递归法
注意:学会在递归遍历的过程中如何记录前后两个指针。
完整代码如下:
class Solution {
TreeNode pre; // 记录上一个遍历的结点
int result = Integer.MAX_VALUE; //存放结果
public int getMinimumDifference(TreeNode root) {
getMin(root);
return result;
}
//将结果存放在result中,所以不需要有返回值
public void getMin(TreeNode cur){
if(cur == null) return;
getMin(cur.left); //左
//中
if(pre != null){
result = Math.min(result, Math.abs(cur.val - pre.val));
}
pre = cur;
getMin(cur.right); //右
}
}
迭代法(中序遍历)
使用中序遍历的
class Solution {
TreeNode pre; // 记录上一个遍历的结点
public int getMinimumDifference(TreeNode root) {
if(root == null) return 0;
Stack<TreeNode> stack = new Stack<>();
int result = Integer.MAX_VALUE;
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
if(cur != null){
stack.push(cur);
cur = cur.left; //左
}else{
cur = stack.pop();
//处理逻辑,中
if(pre != null){
result = Math.min(result, cur.val - pre.val);
}
pre = cur;
cur = cur.right; //右
}
}
return result;
}
}
501.二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
递归法(中序遍历)
在上一题503:搜索树的最小绝对差 中我们就使用了pre指针和cur指针的技巧,这次又用上了。
弄一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
class Solution {
TreeNode pre; //记录前一个遍历的节点
int count = 0; //统计每个元素出现的次数
int maxcount = 0; //统计出现的最大次数
List<Integer> result = new ArrayList<>(); //存放众数结果
public int[] findMode(TreeNode root) {
find(root);
int[] res = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
res[i] = result.get(i);
}
return res;
}
//结果存放在result中,不需要返回值
public void find(TreeNode root){
if(root == null) return;
find(root.left); //左
//中
if(pre == null){ 第一个节点
count = 1;
}else if(pre.val == root.val){ // 与前一个节点数值相同
count++;
}else if(pre.val != root.val){ // 与前一个节点数值不同
count = 1;
}
//众数可能不止一个
if(count == maxcount) result.add(root.val);
if(count > maxcount){
result.clear();
result.add(root.val);
maxcount = count;
}
pre = root; // 更新上一个节点
find(root.right); //右
}
}
迭代法(中序遍历)
迭代法,其实就是迭代法中序遍历的模板加上递归法中中间节点的处理逻辑
class Solution {
public int[] findMode(TreeNode root) {
TreeNode pre = null;
Stack<TreeNode> stack = new Stack<>();
List<Integer> result = new ArrayList<>();
int maxcount = 0;
int count = 0;
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur =cur.left;
}else {
cur = stack.pop();
// 计数
if(pre == null){ 第一个节点
count = 1;
}else if(pre.val == cur.val){ // 与前一个节点数值相同
count++;
}else if(pre.val != cur.val){ // 与前一个节点数值不同
count = 1;
}
//众数可能不止一个
if(count == maxcount) result.add(cur.val);
if(count > maxcount){
result.clear();
result.add(cur.val);
maxcount = count;
}
pre = cur; // 更新上一个节点
cur = cur.right;
}
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
}
236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
需要递归函数返回值,来告诉我们是否找到节点q或者p
求最小公共祖先,需要从底向上遍历,那么二叉树需要通过后序遍历实现从底向上的遍历方式。
在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
如果left 和 right都不为空,说明此时root就是最近公共节点;如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然。
递归法(后序遍历)
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
if(root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q); //左
TreeNode right = lowestCommonAncestor(root.right, p, q); //右
//中
if(left == null && right == null) { // 若未找到节点 p 或 q
return null;
}else if(left == null && right != null) { // 若找到一个节点
return right;
}else if(left != null && right == null) { // 若找到一个节点
return left;
}else { // 若找到两个节点
return root;
}
}
}