前端刷题路-Day68:皇位继承顺序(题号1600)| 8月更文挑战

273 阅读2分钟

皇位继承顺序(题号1600)

题目

一个王国里住着国王、他的孩子们、他的孙子们等等。每一个时间点,这个家庭里有人出生也有人死亡。

这个王国有一个明确规定的皇位继承顺序,第一继承人总是国王自己。我们定义递归函数 Successor(x, curOrder) ,给定一个人 x 和当前的继承顺序,该函数返回 x 的下一继承人。

Successor(x, curOrder):
    如果 x 没有孩子或者所有 x 的孩子都在 curOrder 中:
        如果 x 是国王,那么返回 null
        否则,返回 Successor(x 的父亲, curOrder)
    否则,返回 x 不在 curOrder 中最年长的孩子

比方说,假设王国由国王,他的孩子 AliceBobAliceBob 年长)和 Alice 的孩子 Jack 组成。

  1. 一开始, curOrder["king"].
  2. 调用 Successor(king, curOrder) ,返回 Alice ,所以我们将 Alice 放入 curOrder 中,得到 ["king", "Alice"]
  3. 调用 Successor(Alice, curOrder) ,返回 Jack ,所以我们将 Jack 放入 curOrder 中,得到 ["king", "Alice", "Jack"]
  4. 调用 Successor(Jack, curOrder) ,返回 Bob ,所以我们将 Bob 放入 curOrder 中,得到 ["king", "Alice", "Jack", "Bob"]
  5. 调用 Successor(Bob, curOrder) ,返回 null 。最终得到继承顺序为 ["king", "Alice", "Jack", "Bob"]

请你实现 ThroneInheritance 类:

  • ThroneInheritance(string kingName) 初始化一个 ThroneInheritance 类的对象。国王的名字作为构造函数的参数传入。
  • void birth(string parentName, string childName) 表示 parentName 新拥有了一个名为 childName 的孩子。
  • void death(string name) 表示名为 name 的人死亡。一个人的死亡不会影响 Successor 函数,也不会影响当前的继承顺序。你可以只将这个人标记为死亡状态。
  • string[] getInheritanceOrder() 返回 除去 死亡人员的当前继承顺序列表。

示例

输入:
["ThroneInheritance", "birth", "birth", "birth", "birth", "birth", "birth", "getInheritanceOrder", "death", "getInheritanceOrder"]
[["king"], ["king", "andy"], ["king", "bob"], ["king", "catherine"], ["andy", "matthew"], ["bob", "alex"], ["bob", "asha"], [null], ["bob"], [null]]
输出:
[null, null, null, null, null, null, null, ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"], null, ["king", "andy", "matthew", "alex", "asha", "catherine"]]

解释:
ThroneInheritance t= new ThroneInheritance("king"); // 继承顺序:king
t.birth("king", "andy"); // 继承顺序:king > andy
t.birth("king", "bob"); // 继承顺序:king > andy > bob
t.birth("king", "catherine"); // 继承顺序:king > andy > bob > catherine
t.birth("andy", "matthew"); // 继承顺序:king > andy > matthew > bob > catherine
t.birth("bob", "alex"); // 继承顺序:king > andy > matthew > bob > alex > catherine
t.birth("bob", "asha"); // 继承顺序:king > andy > matthew > bob > alex > asha > catherine
t.getInheritanceOrder(); // 返回 ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"]
t.death("bob"); // 继承顺序:king > andy > matthew > bob(已经去世)> alex > asha > catherine
t.getInheritanceOrder(); // 返回 ["king", "andy", "matthew", "alex", "asha", "catherine"]

提示:

  • 1 <= kingName.length, parentName.length, childName.length, name.length <= 15
  • kingNameparentNamechildNamename 仅包含小写英文字母。
  • 所有的参数 childNamekingName 互不相同。
  • 所有 death 函数中的死亡名字 name 要么是国王,要么是已经出生了的人员名字。
  • 每次调用 birth(parentName, childName) 时,测试用例都保证 parentName 对应的人员是活着的。
  • 最多调用 10^5birthdeath
  • 最多调用 10getInheritanceOrder

链接

leetcode-cn.com/problems/th…

解释

这题啊,这题是阅读理解。

讲真,题目看了得有10分钟,本来其实很简单的一件事,不知道官方为啥要说的这么复杂,看到题目的时候一度有想跳过的冲动。

简单说说一下题目,其实很简答,A有俩儿子,AA和AB,AA有一个儿子,叫AAA,AB有个儿子叫ABA。

轮到要继承A遗产的时候了,按照从年长到年幼的顺序,AA先来,并且AA的后代优先级都比AB高,就酱。

当然了,在分配遗产之前可能有人会GG,GG问题不大,把这个人从继承人名单中去掉就好了,不影响其他人的顺序。

就这,搞得这么复杂,都给我干懵了。

接下来说说解法,这里是笔者想复杂了,笔者是想搞一个对象的结构,里面的后代用Map,因为这样可以保证插入的顺序,大概就是这样的一个结构👇:

var map = {
  status: null,
  children: Map({
    A: {
      status: 'alive',
      children: Map({
        AA: {
          status: 'dead',
          children: Map({
            AAA: ...
          })
        },
        BB: ...
      })
    }
  })
}

对把,最后查的时候进行递归查找,插入的时候需要新建另外一个对象,来标明当前人物前面的人物,以此找到合适的位置进行插入,GG同理,找到合适的人修改statusdead即可。

后来看了答案发现根本就不需要那么复杂,就一个一级的Map来记录人物关系,一个Set来记录是否GG,用Set是因为判断有无更快一些。

然后就完事了,插入的时候直接在根层级插入,不过这里的插入重点是父亲元素,将子元素直接插入父亲元素的数组中。

GG更简单,直接在Setadd一个名字就好。

拿队列的时候搞一个DFS就完事了,一层层找就好,没有难度。

自己的答案

由于答案过于丑陋和复杂就不放了,没有参考价值

更好的方法

先看代码👇:

var ThroneInheritance = function(kingName) {
  this.relation = new Map()
  this.dead = new Set()
  this.king = kingName
};

ThroneInheritance.prototype.birth = function(parentName, childName) {
  if (!this.relation.has(parentName)) {
    this.relation.set(parentName, [])
  }
  this.relation.get(parentName).push(childName)
};

ThroneInheritance.prototype.death = function(name) {
  this.dead.add(name)
};

ThroneInheritance.prototype.getInheritanceOrder = function() {
  var arr = []
  function DFS(name) {
    if (!this.dead.has(name)) arr.push(name)
    if (this.relation.has(name)) {
      for (const childName of this.relation.get(name)) {
        DFS.call(this, childName)
      }
    }
  }
  DFS.call(this, this.king)
  return arr
};

birth那里是先判断parentName是否存在,不存在就加一个属性,初始后赋值为空数组,之后将childName推入数组。

getInheritanceOrder就是一个DFS,首先看看是不是GG,如果没GG就加入数组,之后判断有没有子元素,如果有子元素,遍历子元素的name,重复寻找即可。

这里由于用的是function,所以需要用call来改变this指向,否则this会指向全局window对象,如果用箭头函数就没有这个问题了。



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)