leetcode
leetcode 1451 ~ 1500
王位继承顺序

王位继承顺序

难度:

标签:

题目描述

代码结果

运行时间: 289 ms, 内存: 63.8 MB


/*
 * 思路:
 * 1. 与普通Java实现相同,但使用Stream API简化某些操作。
 * 2. 使用哈希表来存储家族关系,使用集合来记录死亡人员。
 * 3. 在获取继承顺序时,使用Stream过滤死亡人员。
 */
import java.util.*;
import java.util.stream.Collectors;

class ThroneInheritance {
    private String king;
    private Map<String, List<String>> family;
    private Set<String> dead;

    public ThroneInheritance(String kingName) {
        this.king = kingName;
        this.family = new HashMap<>();
        this.family.put(kingName, new ArrayList<>());
        this.dead = new HashSet<>();
    }

    public void birth(String parentName, String childName) {
        family.computeIfAbsent(parentName, k -> new ArrayList<>()).add(childName);
        family.put(childName, new ArrayList<>());
    }

    public void death(String name) {
        dead.add(name);
    }

    public List<String> getInheritanceOrder() {
        List<String> order = new ArrayList<>();
        getInheritanceOrderStream(king).forEach(order::add);
        return order;
    }

    private Stream<String> getInheritanceOrderStream(String person) {
        return Stream.concat(
            dead.contains(person) ? Stream.empty() : Stream.of(person),
            family.getOrDefault(person, Collections.emptyList())
                .stream()
                .flatMap(this::getInheritanceOrderStream)
        );
    }
}

解释

方法:

该题解采用了树形数据结构来模拟继承关系,使用散列表(hash)存储每个人与其孩子们的关系,以及一个集合(dead)记录死亡人员。当调用birth函数时,孩子会被添加到对应父母的列表中。death函数只将人标记为死亡,不从树中删除。继承顺序是通过先序遍历(preOrder)树来得到的,同时在遍历过程中跳过标记为死亡的人。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在`ThroneInheritance`类中,`birth`函数添加孩子时是否考虑了孩子的出生顺序,以保证继承顺序的正确性?
在`ThroneInheritance`类的`birth`函数中,每当添加一个孩子时,该孩子被添加到父亲名下的列表的末尾。由于列表是保持元素添加顺序的数据结构,因此孩子的出生顺序被自然记录下来。继承顺序的遍历(即先序遍历)时,将会按照这个顺序访问孩子,确保了继承顺序的正确性。
🦆
你提到`death`函数只是将人标记为死亡而不从树中删除,这种设计有什么特定的优势吗?
将人标记为死亡而不从树结构中直接删除有几个优势:首先,这样可以避免修改树的结构,维护简单,尤其在涉及到复杂的父子关系时;其次,这种方式可以快速地标记一个人的死亡状态,并且在生成继承顺序时通过简单地检查死亡集合来跳过这些人,这样可以在不重新构建树的情况下快速更新继承顺序;最后,即使某些成员已经标记为死亡,他们的存在仍可能对理解整个家族树的结构和后续操作有用。
🦆
在`getInheritanceOrder`函数中,先序遍历时跳过了已死亡的人。这种处理方式是否会影响遍历的效率,尤其是当死亡人数很多时?
当死亡人数较多时,这种处理方式确实可能影响遍历的效率。因为即使一个人已经死亡,其下的所有子孙还是会被递归遍历一遍,只是在添加到结果列表时被跳过。这意味着如果大量的人已经死亡,尤其是在树的上层,仍然需要进行大量的无效遍历。尽管如此,由于不需要重构树,这种方式在实现简单性和避免频繁修改树结构的情况下还是有其效率和实用性。
🦆
请问为什么选择使用散列表来存储每个人的孩子,而不是其他数据结构如二叉树或链表?
选择使用散列表来存储每个人的孩子列表主要是因为散列表提供了快速的查找、插入和删除操作。在继承树中,可能需要频繁地查找某个人的孩子或向某个人的孩子列表中添加新的孩子,散列表使这些操作的时间复杂度平均为O(1)。而如果使用链表,虽然插入操作快速,但查找特定人的孩子需要O(n)的时间复杂度;二叉树提供了较好的平衡查找性能,但对于动态变化的大家族树来说,可能会面临频繁的重平衡问题。因此,散列表在这种用例中提供了一种既快速又简单的解决方案。

相关问题