我是靠谱客的博主 称心毛巾,最近开发中收集的这篇文章主要介绍5848. 树上的操作,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

给你一棵 n 个节点的树,编号从 0 到 n - 1 ,以父节点数组 parent 的形式给出,其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点,所以 parent[0] = -1 ,因为它没有父节点。你想要设计一个数据结构实现树里面对节点的加锁,解锁和升级操作。

数据结构需要支持如下函数:

  • Lock:指定用户给指定节点 上锁 ,上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下,才能进行上锁操作。
  • Unlock:指定用户给指定节点 解锁 ,只有当指定节点当前正被指定用户锁住时,才能执行该解锁操作。
  • Upgrade:指定用户给指定节点 上锁 ,并且将该节点的所有子孙节点 解锁 。只有如下 3 个条件 全部 满足时才能执行升级操作:
  1. 指定节点当前状态为未上锁。
  2. 指定节点至少有一个上锁状态的子孙节点(可以是 任意 用户上锁的)。
  3. 指定节点没有任何上锁的祖先节点。
    请你实现 LockingTree 类:
LockingTree(int[] parent) 用父节点数组初始化数据结构。
lock(int num, int user) 如果 id 为 user 的用户可以给节点 num 上锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 id 为 user 的用户 上锁 。
unlock(int num, int user) 如果 id 为 user 的用户可以给节点 num 解锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 变为 未上锁 状态。
upgrade(int num, int user) 如果 id 为 user 的用户可以给节点 num 升级,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 升级 。

示例 1:


输入:
["LockingTree", "lock", "unlock", "unlock", "lock", "upgrade", "lock"]
[[[-1, 0, 0, 1, 1, 2, 2]], [2, 2], [2, 3], [2, 2], [4, 5], [0, 1], [0, 1]]
输出:
[null, true, false, true, true, true, false]

解释:
LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]);
lockingTree.lock(2, 2);    // 返回 true ,因为节点 2 未上锁。
                           // 节点 2 被用户 2 上锁。
lockingTree.unlock(2, 3);  // 返回 false ,因为用户 3 无法解锁被用户 2 上锁的节点。
lockingTree.unlock(2, 2);  // 返回 true ,因为节点 2 之前被用户 2 上锁。
                           // 节点 2 现在变为未上锁状态。
lockingTree.lock(4, 5);    // 返回 true ,因为节点 4 未上锁。
                           // 节点 4 被用户 5 上锁。
lockingTree.upgrade(0, 1); // 返回 true ,因为节点 0 未上锁且至少有一个被上锁的子孙节点(节点 4)。
                           // 节点 0 被用户 1 上锁,节点 4 变为未上锁。
lockingTree.lock(0, 1);    // 返回 false ,因为节点 0 已经被上锁了。

提示:

  • n == parent.length
  • 2 <= n <= 2000
  • 对于 i != 0 ,满足 0 <= parent[i] <= n - 1
  • parent[0] == -1
  • 0 <= num <= n - 1
  • 1 <= user <= 104
  • parent 表示一棵合法的树。
  • lock ,unlock 和 upgrade 的调用 总共 不超过 2000 次。

解题思路

使用map维护被锁节点和加锁者的关系,再使用一个map维护父节点和对应子节点之间的关系

lock

判断是否有锁,如果没有,则可以直接加锁

unlock

判断当前锁的加锁者是否为自己

upgrade

  1. 先向上遍历祖先节点和加锁节点,判断是否有加锁
  2. 再遍历子孙节点,判断是否加锁
  3. 给所有子孙节点解锁,给当前节点加锁

代码

    class LockingTree {

        int[] p;
        Map<Integer, Integer> locked = new HashMap<>();
        Map<Integer,Set<Integer>> child=new HashMap<>();
        public LockingTree(int[] parent) {
            p = parent;
            for (int i = 0; i < parent.length; i++) {
                if (!child.containsKey(p[i]))
                    child.put(p[i],new HashSet<>());
                child.get(p[i]).add(i);
            }
        }

        public boolean lock(int num, int user) {
            if (locked.containsKey(num) )
                return false;
            locked.put(num, user);
            return true;
        }

        public boolean unlock(int num, int user) {
            if (locked.containsKey(num) && locked.get(num) == user) {
                locked.remove(num);
                return true;
            } else return false;
        }
        public boolean dfs(int num) {

            while (num!=-1)
            {
                if(locked.containsKey(num))
                    return false;
                num=p[num];
            }
            return true;
        }
        public boolean ddfs(int num,int f) {

            if (locked.containsKey(num)&&num!=f){
                return true;
            }
            boolean res=false;
            if (child.containsKey(num))
            {
                for (Integer integer : child.get(num)) {
                    res|=ddfs(integer,f);
                }
            }
            return res;
        }
        public void dddfs(int num) {

            locked.remove(num);
            if (child.containsKey(num))
            {
                for (Integer integer : child.get(num)) {
                    dddfs(integer);
                }
            }
            
        }
        public boolean upgrade(int num, int user) {
            if (dfs(num)&&ddfs(num,num))
            {
                dddfs(num);
                locked.put(num, user);
                return true;
            }
            return false;

        }
    }

/**
 * Your LockingTree object will be instantiated and called as such:
 * LockingTree obj = new LockingTree(parent);
 * boolean param_1 = obj.lock(num,user);
 * boolean param_2 = obj.unlock(num,user);
 * boolean param_3 = obj.upgrade(num,user);
 */

/**
 * Your LockingTree object will be instantiated and called as such:
 * LockingTree obj = new LockingTree(parent);
 * boolean param_1 = obj.lock(num,user);
 * boolean param_2 = obj.unlock(num,user);
 * boolean param_3 = obj.upgrade(num,user);
 */

最后

以上就是称心毛巾为你收集整理的5848. 树上的操作的全部内容,希望文章能够帮你解决5848. 树上的操作所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部