我需要一个存储子集的数据结构 - 称之为{1 ,. 。 。 ,n}(n最初给出) 并支持这些操作:
•最初:给出n,S = {1 ,. 。 。 ,n}在开头。
•删除(i):从S中删除i。如果我已经不在S中,则无效。
•pred(i):返回i中S的前身。这意味着max {j∈S| j<我是S中最伟大的元素 这严格低于我。如果没有,则返回0.参数i保证在{1 ,. 。 。 ,n}, 但可能会或可能不会在S。
例如,如果n = 7且S = {1,3,6,7},则pred(1)返回0,pred(2)和pred(3)返回1.
我需要弄明白:
感谢任何帮助(我不需要代码 - 只需算法)。
答案 0 :(得分:5)
您可以使用Disjoint-set data structure。
让我们将子集表示为不相交集。不相交集的每个元素是子集driver.find_elements_by_partial_link_text("Wat Chedi Luang").click()
的元素(包括始终呈现零)与集合中所有缺少的元素联合,该元素大于i
且小于下一个集合元素。
示例:
i
最初,我们有一个由n = 10
s = [1, 4, 7, 8], disjoint-set = [{0}, {1,2,3}, {4,5,6}, {7}, {8, 9, 10}]
s = [3, 5, 6, 10], disjoint-set = [{0, 1, 2}, {3, 4}, {5}, {6, 7, 8, 9}, {10}]
不相交集元素表示的完整集(包括零)。通常,每个disjoint-set元素都是一个有根的树,我们可以在每个树根的元素中存储n+1
个数字。
我们leftmost
是包含leftmost(i)
的不相交集元素的leftmost
值。
i
操作类似于不相交集的Find操作。我们只是从leftmost(i)
转到元素的根,并返回为根存储的i
数字。 复杂性:leftmost
我们可以检查O(α(n))
与i
比较的子集中是否i
。如果它们相等(leftmost(i)
),那么i > 0
就在子集中。
i
不在子集中,则 pred(i)
将等于leftmost(i)
,如果i
在子集中,则leftmost(i-1)
等于i
。 复杂性:O(α(n))
在每个delete(i)
操作中,我们首先检查i
是否在子集中。如果i
在子集中,我们应该将包含i
的元素与左邻居元素(这是包含i-1
的元素)结合起来。此操作类似于不相交集的Union操作。结果树的leftmost
个数将等于leftmost(i-1)
。 复杂性:O(α(n))
编辑:我刚才注意到问题中“严格少于我”,稍微改了一下说明。
答案 1 :(得分:1)
我不确定是否存在可以在O(α(n))时间内保证所有这些属性的数据结构,但是良好的开端将是诸如van Emde Boas trees或{{3}之类的前任数据结构}
vEB树的工作原理是基于元素索引的二进制表示来递归定义的。假设对于某些b = 2 ^ k
,n = 2 ^ b如果我们只有两个元素,请存储最小值和最大值
否则,我们将所有元素的二进制表示分为上部和下部b / 2位 我们为所有元素的高位构建vEB树('summary'),为低位构建√nvBE树(每个高位的选择一个)。此外,我们存储最小和最大元素。
这为您提供了O(n)空间使用和O(log log n)= O(k)搜索,插入和删除的时间。
但请注意,所涉及的常数因素可能非常大。如果您的n
代表32位,至少我知道Dementiev等人的y-fast tries。当问题大小可以通过其他技术更容易解决时打破递归
y-fast尝试的想法建立在x-fast尝试上:
它们最简单地描述为基于其元素的二进制表示的trie,结合每个级别的哈希表和一些额外的指针。
y-fast尝试通过在几乎相等大小的分区中拆分元素并从中选择代表(最大值)来减少空间使用,在其上构建x-fast trie。然后使用常规平衡搜索树实现分区内的搜索。
空间使用和时间复杂度与vEB相当。我猜这些常数因素比vEB的天真实现要小一些,但声称只是基于直觉。
最后一点:始终牢记日志日志n< 6 ,在不久的将来可能不会改变
答案 2 :(得分:0)
在提供O(α(n))时间方面,它确实变得棘手。以下是我对此的看法:
由于我们知道的i
范围是1
到n
,我们可以先形成一个自平衡的BST,如AVL tree
。该AVL树的节点应该是DataNode的对象。这是它的样子:
public class DataNode{
int value;
boolean type;
DataNode(int value, boolean type){
this.value = value;
this.type = type;
}
}
value
只包含范围1到n中的所有值。如果我们在树中插入的项目存在于集合S中,则type
变量将被赋值为true
。如果不是,则将其标记为false
。
创建需要O(n)时间。删除可以在O(logn)
时间内完成。
对于pred(i),如果我是正确的,我们可以将平均时间复杂度设置为O(logn)
左右。 pred(i)的算法应该是这样的:
i
。如果type为true,则返回此元素i
的inorder前导码,如果此前一个的类型值为true
。 false
,则重复此元素的下一个前任(即i-1的前身),直到我们找到一个type = true
的元素。type = true
这样的前任,则返回0。我希望我们可以进一步优化这种方法,使其成为对于pred(i)的O(α(n))。