螺旋计划第一阶段 35题

这篇博客介绍了如何找到二叉树中两个节点的最近公共祖先,分别提供了递归和非递归两种解决方案。递归方法通过判断当前节点是否包含目标节点来逐步缩小范围。非递归方法则利用哈希表存储节点的父节点,从p和q节点向上遍历,找到首次出现的共同祖先。此外,还提到了LRU缓存的实现,使用LinkedHashMap并调整访问顺序。
摘要由CSDN通过智能技术生成

二叉树

二叉树的最近公共祖先

递归:

public class LowestCommonAncestor {
    private TreeNode answer;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        ifHavePorQ(root, p, q);
        return answer;
    }

    // 这道题的难点在于 你不要去想公共父结点的递归,你要去想左右子树里有没有p或者q,如果左右子树都有p或q
    // 那么公共父结点就是root(我称之为异构的情况),或者另外一个场景,p或q本身就是另一个的公共父结点,(我称之为同构)
    public boolean ifHavePorQ(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null) {
            return false;
        }
        boolean ifLeftHasPorQ = ifHavePorQ(root.left, p,q);
        boolean ifRightHasPorQ = ifHavePorQ(root.right,p,q);
        if((ifLeftHasPorQ&&ifRightHasPorQ) || (( root.val==p.val || root.val==q.val)&&(ifLeftHasPorQ||ifRightHasPorQ)))
        {
            answer = root;
        }
        // 这就是左右子树里有没有p或者q的条件
        return ifLeftHasPorQ || ifRightHasPorQ || root.val==p.val || root.val==q.val;
    }

}

非递归:

方法二:存储父节点
思路

我们可以用哈希表存储所有节点的父节点,然后我们就可以利用节点的父节点信息从 p 结点开始不断往上跳,并记录已经访问过的节点,再从 q 节点开始不断往上跳,如果碰到已经访问过的节点,那么这个节点就是我们要找的最近公共祖先。

算法

从根节点开始遍历整棵二叉树,用哈希表记录每个节点的父节点指针。
从 p 节点开始不断往它的祖先移动,并用数据结构记录已经访问过的祖先节点。
同样,我们再从 q 节点开始不断往它的祖先移动,如果有祖先已经被访问过,即意味着这是 p 和 q 的深度最深的公共祖先,即 LCA 节点。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        HashMap<TreeNode, TreeNode> myHashMap = new HashMap<>();
        preOrder(root, myHashMap);

        Set<TreeNode> fathersOfP = new HashSet();
        TreeNode cur = p;
        while(cur!=null) {
            fathersOfP.add(cur);
            cur=myHashMap.get(cur);
        }

        cur=q;
        while(cur!=null) {
            if(fathersOfP.contains(cur)) {
                return cur;
            }
            cur=myHashMap.get(cur);
        }
        return null;
    }

    public void preOrder(TreeNode root, HashMap<TreeNode, TreeNode> myHashMap) {
        if(root==null) {
            return;
        }
        if(root.left!=null) {
            myHashMap.put(root.left, root);
            preOrder(root.left, myHashMap);
        }
        if(root.right!=null) {
            myHashMap.put(root.right, root);
            preOrder(root.right, myHashMap);
        }
    }
}

LRU

LRU可以使用LinkedHashMap实现

 accessOrder是true就是按照get的顺序调整,最近访问过的放到链表尾部

false就是按照插入顺序

afterNodeAccess 就是在node被访问过后,调整它到链表尾部,这个方法在hashmap的get put等都会调用

afterNodeInsertion 默认是不删除结点,可以override这个里面的

removeEldestEntry函数

这样就可以在size>容量的时候,把头结点,最不常用的删除

可以参考博客(就参考这个博客就足够了)

超详细LinkedHashMap解析_求offer的菜鸡的博客-CSDN博客_linkedhashmap

public class LinkedHashMapCache extends LinkedHashMap {
    private int capacity;
    public LinkedHashMapCache(int capacity) {
        // accsessOrder为true
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return (int)super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key,value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值