1(70)
/ \
/ \
2(40) 5(10)
/ \ \
/ \ \
3(60) 4(80) 6(20)
/ \
/ \
7(30) 8(50)
这是针对在线挑战(非现场比赛)。我不需要有人为我解决,只是为了向正确的方向努力。试着学习。
每个节点都有一个唯一的ID,没有两个人有相同的工资。例如,#1人的工资为70美元,第7人的工资为30美元。树结构表示谁监督谁。问题是谁对一个人的下属的工资最低。
例如,我选择#2人。下属中谁是第二低? #2的下属是3,4,7,8。第二低的工资是属于#8的50美元。
有很多查询,所以结构必须高效。
我考虑过这个问题并研究了数据结构。二叉树似乎是一个好主意,但我需要帮助。
例如,对于#2号人物,我认为理想的结构看起来像是
2(40)
/ \
/ \
7(30) 3(60)
/ \
/ \
8(50) 4(80)
每个子节点都是#2的下属,每个左侧分支的工资都低于右边。如果我在每个节点存储多少个孩子,我可以得到最低的k。
例如:从#2开始,左分支1节点,右分支3节点。所以第二低 - 1表示我现在想要在右分支中的第一低。
移动到#3,第一个最低点到#8,50美元是正确的。
我的问题:
我认为这种做法很好吗?这是一种有效的方法吗?
我无法弄清楚如何构建这种树。我想我可以递归地制作它们。但很难弄清楚如何让所有孩子按工资分类到新树。需要一些帮助。
答案 0 :(得分:2)
这是一个使用O(n log ^ 2 n + q log n)时间和O(n log ^ 2 n)空间的解决方案(后者计数不是最好的,但考虑到限制,可能还不错)。< / p>
使用以下操作和某种迭代方式实现纯函数排序列表(作为扩充二进制搜索树)。
EmptyList() -> returns the empty list
Insert(list, key) -> returns the list where |key| has been inserted into |list|
Length(list) -> returns the length of the list
Get(list, k) -> returns the element at index |k| in |list|
在这些操作之上,实现操作
Merge(list1, list2) -> returns the union of |list1| and |list2|
将较短列表的元素插入较长的列表中。
现在做一件显而易见的事情:将员工层次结构从叶子遍历到根目录,将每个员工的有序列表设置为适当的下级列表合并,并回答查询。
每个查询都需要O(log n)时间。分析中有趣的部分与预处理有关。
预处理的成本主要取决于调用Insert()
的成本,特别是来自Merge()
,因为还有其他n个插入。每次插入需要O(log n)时间并花费O(log n)空间(以单词测量)。
使预处理不是二次方的是隐式heavy path decomposition。每次我们合并两个列表时,两个列表都不会随后合并。由于较短的列表被插入较长的列表,每次将一个键插入列表时,该列表至少是先前插入该键的列表的两倍。因此,每个密钥最多是lg n个插入的主题,这足以建立整体O(n log n)插入的边界,从而确定所声明的资源边界。
答案 1 :(得分:0)
这是一种可能的解决方案。对于每个节点,我们将构造一个包含该节点的所有子节点值的数组,并按排序顺序保存。我们正在寻找的结果是
形式的字典{ 1 : [10, 20, 30, 40, 60 80],
2 : [30, 50, 60, 80]
...
}
一旦我们有了这个,要查询第i个最低工资的任何节点,只需获取数组的第i个元素。执行所有查询的总时间是O(q),其中q是查询的数量。
我们如何构建这个?假设您有一个指向根节点的指针,您可以递归地为每个子节点构建已排序的工资。将这些值存储在结果中。复制每个孩子的数组,并将每个孩子的薪水插入到孩子的复制数组中。使用二进制搜索来查找位置,因为每个数组都已排序。现在你有了k个排序数组,你将它们合并以获得一个排序数组。如果要合并两个数组,可以在线性时间内完成。只需循环,选择每次较小的数组的第一个元素。
对于每个节点有2个子节点的情况,合并两个子节点的数组是O(n)tine。由于我们使用二进制搜索,因此将每个节点的工资插入其相应的数组是每个节点的O(log(n))。复制children数组是O(n),并且有n个节点,因此我们有O(n ^ 2)个总预处理时间。
总运行时间为O(n ^ 2 + q)
如果我们不能假设每个节点最多有2个孩子怎么办?然后合并数组,使用this算法。这在O(nlog(k))中运行,其中k是要合并的数组的数量,因为我们每个元素从堆中弹出一次,并且当存在k个数组时,调整堆的大小需要O(log(k))。 k<=n
所以我们可以将其简化为O(nlog(n))。因此总运行时间不变。
该解决方案的空间复杂度为O(n ^ 2)。
答案 2 :(得分:0)
这个问题有两个部分:第一,找到指定的人,然后找到第k个从属人。 由于树不按id排序,因此要通过id查找指定的perspn,需要遍历整个树,直到找到指定的id。为了加快这一部分,我们可以构建一个哈希映射,它允许我们在O(1)时间内通过id找到人员节点,并且需要O(n)空间和设置时间。 然后,为了找到第k个最低工资的下属,我们需要搜索子树。由于它没有按工资排序,我们必须扫描整个子树并找到第k个最低工资。这可以使用数组或堆来完成(将子树节点放入数组或堆中)。第二部分是O(m log k)时间,使用堆来保持最低的k项,其中m是子坐标的数量,并且需要O(k)空间。如果m(指定人的下属数)和k很小,这应该是可以接受的。