[英]fast way to check if subset contains a given list of subsets
我的問題如下
我有一套K元素
該集合的每個子集由std :: bitset的實例表示(位i為真=子集中有元素i)
我有一個輸入子集I,以及一個子集S1 ... Sn的列表
我想從S1 ... Sn中返回項目,這樣Si就包含在I中。(也就是說,每次Si有一點真實,它在I中也必須是真的)
顯然,這可以在K * n中完成,通過對每個S子集進行獨立的相同檢查。
但是,有沒有一種通用的方法可以做得更好? 我很確定這是可能的,因為在我的情況下,子集列表S1 ... Sn總是相同的並且可以進行預處理。 我確定可以將子集存儲在特定的數據結構中(樹?trie?),這樣我就可以一次性丟棄很多相同的數據結構等等。
example :
K = 5
I = [1,1,0,1,0]
S1 = [1,0,0,0,0]
S2 = [1,1,0,1,0]
S3 = [1,1,1,0,0]
the ouput should return S1,S2 (not S3!)
我有一個常數集S1,S2,...,Sn
,並在同一組上運行不同的I
查詢。
編輯:我正在談論的例子:例如,如果S2包含在S2中:檢查I中是否包含S1:如果不包括,那么如果S3是S1的並集,則S2不能包含在I中(不需要檢查) S2:如果S1和S2包含在I中,則S3也是如此
您可以使用倒排索引方法。 雖然它不會改善最壞情況的性能,但它可能會加速平均情況,特別是對於相對密集的查詢向量。
對於每個j = 1,2,...,k,創建一個排序列表,其中如果j
在S_i
,則每個子集都在此列表中。 在預處理中僅創建一次。
在您的示例中,它將類似於:
0 -> [S1,S2,S3]
1 -> [S2,S3]
2 -> [S3]
3 -> [S2]
4 -> []
現在,給定一個查詢I
發現,包括“下降”位中的一個所有集合I
。 這與信息檢索中的OR查詢相同。 此查詢的答案是結果中沒有的子集。 剩下的就是。
在您的示例中,查詢為2 OR 4
,查詢反向索引時的結果為: S3
,因此結果為S1,S2。
這基本上就是搜索引擎所做的事情,如果查詢與可能性的數量相比包含的條款非常少,則效率非常高。
用部分答案回答我的問題:
現在問題是,如何從1)最佳地構建樹? 即,具有最大深度和最小“寬度”的例如,在我的例子中,“壞”樹將是S1,S2和S3是來自根節點的子節點。 “好”樹將是根節點僅具有針對子節點的S1,並且以S1為根的樹具有S2且S3為子節點。 我不知道如何構建這棵樹
構造具有所有S1...Sn
的二叉樹T
,其中每個級別k具有兩個子節點,這取決於S
在位置k
是0
還是1
。 樹的葉子都是你的S1...Sn
。
給定輸入子集I
讓我們取Ik
(位置k中的元素):如果Ik==0
,則在級別K
對應於0的T
的子樹。如果Ik==1
,則在級別K
選擇T
子樹。 在T上以這種方式進行,直到你到達所有的葉子。
在最壞的情況下,您對給定的 I
進行O(n+k)
運算。
由於S1...Sn
不會改變,因此構造樹T
是一次操作。
編輯:我的答案很倉促。 樹T
具有多於n
葉子,它具有2^k=m
葉子。 但我們可以刪除不在S1...Sn
中的葉子S1...Sn
和死亡的子樹。 這將成本分析帶到O(2^k)
但實際上我們將有更少的節點。 現在分析變得更難,如果它的價值取決於m
和n
之間的比率;
我提出了一種不同的分析方法:認為在k級我們在恆定時間內丟棄所有在級別為k
無效位的子集S
,但是我們必須在每個級別的O(n)
子樹中這樣做。 由於該操作重復k
次,因此最大成本為O(kn)
,但實際上平均值較低。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.