|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[1600. 皇位继承顺序](https://leetcode-cn.com/problems/throne-inheritance/solution/gong-shui-san-xie-shi-yong-dan-xiang-lia-7t65/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「单链表」、「哈希表」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +一个王国里住着国王、他的孩子们、他的孙子们等等。每一个时间点,这个家庭里有人出生也有人死亡。 |
| 10 | + |
| 11 | +这个王国有一个明确规定的皇位继承顺序,第一继承人总是国王自己。我们定义递归函数 Successor(x, curOrder) ,给定一个人 x 和当前的继承顺序,该函数返回 x 的下一继承人。 |
| 12 | +``` |
| 13 | +Successor(x, curOrder): |
| 14 | + 如果 x 没有孩子或者所有 x 的孩子都在 curOrder 中: |
| 15 | + 如果 x 是国王,那么返回 null |
| 16 | + 否则,返回 Successor(x 的父亲, curOrder) |
| 17 | + 否则,返回 x 不在 curOrder 中最年长的孩子 |
| 18 | +``` |
| 19 | +比方说,假设王国由国王,他的孩子 Alice 和 Bob (Alice 比 Bob 年长)和 Alice 的孩子 Jack 组成。 |
| 20 | + |
| 21 | +1. 一开始, curOrder 为 ["king"]. |
| 22 | +2. 调用 Successor(king, curOrder) ,返回 Alice ,所以我们将 Alice 放入 curOrder 中,得到 ["king", "Alice"] 。 |
| 23 | +3. 调用 Successor(Alice, curOrder) ,返回 Jack ,所以我们将 Jack 放入 curOrder 中,得到 ["king", "Alice", "Jack"] 。 |
| 24 | +4. 调用 Successor(Jack, curOrder) ,返回 Bob ,所以我们将 Bob 放入 curOrder 中,得到 ["king", "Alice", "Jack", "Bob"] 。 |
| 25 | +5. 调用 Successor(Bob, curOrder) ,返回 null 。最终得到继承顺序为 ["king", "Alice", "Jack", "Bob"] 。 |
| 26 | +通过以上的函数,我们总是能得到一个唯一的继承顺序。 |
| 27 | + |
| 28 | +请你实现 ThroneInheritance 类: |
| 29 | + |
| 30 | +* ThroneInheritance(string kingName) 初始化一个 ThroneInheritance 类的对象。国王的名字作为构造函数的参数传入。 |
| 31 | +* void birth(string parentName, string childName) 表示 parentName 新拥有了一个名为 childName 的孩子。 |
| 32 | +* void death(string name) 表示名为 name 的人死亡。一个人的死亡不会影响 Successor 函数,也不会影响当前的继承顺序。你可以只将这个人标记为死亡状态。 |
| 33 | +* string[] getInheritanceOrder() 返回 除去 死亡人员的当前继承顺序列表。 |
| 34 | + |
| 35 | +示例: |
| 36 | +``` |
| 37 | +输入: |
| 38 | +["ThroneInheritance", "birth", "birth", "birth", "birth", "birth", "birth", "getInheritanceOrder", "death", "getInheritanceOrder"] |
| 39 | +[["king"], ["king", "andy"], ["king", "bob"], ["king", "catherine"], ["andy", "matthew"], ["bob", "alex"], ["bob", "asha"], [null], ["bob"], [null]] |
| 40 | +
|
| 41 | +输出: |
| 42 | +[null, null, null, null, null, null, null, ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"], null, ["king", "andy", "matthew", "alex", "asha", "catherine"]] |
| 43 | +
|
| 44 | +解释: |
| 45 | +ThroneInheritance t= new ThroneInheritance("king"); // 继承顺序:king |
| 46 | +t.birth("king", "andy"); // 继承顺序:king > andy |
| 47 | +t.birth("king", "bob"); // 继承顺序:king > andy > bob |
| 48 | +t.birth("king", "catherine"); // 继承顺序:king > andy > bob > catherine |
| 49 | +t.birth("andy", "matthew"); // 继承顺序:king > andy > matthew > bob > catherine |
| 50 | +t.birth("bob", "alex"); // 继承顺序:king > andy > matthew > bob > alex > catherine |
| 51 | +t.birth("bob", "asha"); // 继承顺序:king > andy > matthew > bob > alex > asha > catherine |
| 52 | +t.getInheritanceOrder(); // 返回 ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"] |
| 53 | +t.death("bob"); // 继承顺序:king > andy > matthew > bob(已经去世)> alex > asha > catherine |
| 54 | +t.getInheritanceOrder(); // 返回 ["king", "andy", "matthew", "alex", "asha", "catherine"] |
| 55 | +``` |
| 56 | + |
| 57 | +提示: |
| 58 | +* 1 <= kingName.length, parentName.length, childName.length, name.length <= 15 |
| 59 | +* kingName,parentName, childName 和 name 仅包含小写英文字母。 |
| 60 | +* 所有的参数 childName 和 kingName 互不相同。 |
| 61 | +* 所有 death 函数中的死亡名字 name 要么是国王,要么是已经出生了的人员名字。 |
| 62 | +* 每次调用 birth(parentName, childName) 时,测试用例都保证 parentName 对应的人员是活着的。 |
| 63 | +* 最多调用 $10^5$ 次birth 和 death 。 |
| 64 | +* 最多调用 10 次 getInheritanceOrder 。 |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +### 单向链表 & 标记删除 |
| 69 | + |
| 70 | +根据题意,我们需要将「新儿子」插入到「父亲」的「最后一个儿子」的「儿子们」的后面(**注意这是个递归过程**);如果该「父亲」还没有任何儿子,则直接插到「父亲」后面。 |
| 71 | + |
| 72 | +因此,我们需要在节点 `Node` 中使用一个 `last` 记录该节点的「最后一个儿子」,同时因为删除的时候,我们无法在 $O(1)$ 的复杂度内更新 `last` 信息,所以只能使用「标记删除」的方式。 |
| 73 | + |
| 74 | + |
| 75 | + |
| 76 | +代码: |
| 77 | +```Java [] |
| 78 | +class ThroneInheritance { |
| 79 | + class Node { |
| 80 | + String name; |
| 81 | + Node next; |
| 82 | + Node last; // 记录最后一个儿子 |
| 83 | + boolean isDeleted = false; |
| 84 | + Node (String _name) { |
| 85 | + name = _name; |
| 86 | + } |
| 87 | + } |
| 88 | + Map<String, Node> map = new HashMap<>(); |
| 89 | + Node head = new Node(""), tail = new Node(""); |
| 90 | + public ThroneInheritance(String name) { |
| 91 | + Node root = new Node(name); |
| 92 | + root.next = tail; |
| 93 | + head.next = root; |
| 94 | + map.put(name, root); |
| 95 | + } |
| 96 | + |
| 97 | + public void birth(String pname, String cname) { |
| 98 | + Node node = new Node(cname); |
| 99 | + map.put(cname, node); |
| 100 | + Node p = map.get(pname); |
| 101 | + Node tmp = p; |
| 102 | + while (tmp.last != null) tmp = tmp.last; |
| 103 | + node.next = tmp.next; |
| 104 | + tmp.next = node; |
| 105 | + p.last = node; |
| 106 | + } |
| 107 | + |
| 108 | + public void death(String name) { |
| 109 | + Node node = map.get(name); |
| 110 | + node.isDeleted = true; |
| 111 | + } |
| 112 | + |
| 113 | + public List<String> getInheritanceOrder() { |
| 114 | + List<String> ans = new ArrayList<>(); |
| 115 | + Node tmp = head.next; |
| 116 | + while (tmp.next != null) { |
| 117 | + if (!tmp.isDeleted) ans.add(tmp.name); |
| 118 | + tmp = tmp.next; |
| 119 | + } |
| 120 | + return ans; |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | +* 时间复杂度:`birth` 和 `getInheritanceOrder` 操作为 $O(n)$;其余操作为 $O(1)$ |
| 125 | +* 时间复杂度:$O(n)$ |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +### 最后 |
| 130 | + |
| 131 | +这是我们「刷穿 LeetCode」系列文章的第 `No.1600` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。 |
| 132 | + |
| 133 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 134 | + |
| 135 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 136 | + |
| 137 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 138 | + |
0 commit comments