我有一组位模式,想要找到集合中与给定输入匹配的元素的索引。位模式包含“不关心”位,即x-es,它匹配0和1。
示例 位模式集是
index abcd
0 00x1
1 01xx
2 100x
3 1010
4 1x11
然后,尝试匹配0110应返回索引1,而1011应返回索引4.
如何通过元素线性搜索更快地解决这个问题?我想可以制作一种二叉树,但是,创建这样一棵树的智能方法是什么?是否存在针对此类问题的其他有效数据结构/算法,主要是在查询效率和存储要求方面。
我有两种不同的情况需要解决这个问题
更新 x-es比其他位置更有可能出现在某些位位置,也就是说,某些位位置将由x-es支配,而其他位将主要为零/ 1。
答案 0 :(得分:2)
我认为你可以为位模式构建一个trie树,该节点包含模式的原始索引。
完成匹配只是在trie树中搜索,当trie节点包含相同的'x'位时,转到下一个节点。结果可能包含特定输入的多个索引。
这是我的解决方案,
public class Solution {
public static class Trie<T> {
private final Character WILD = 'x';
private Map<Character, Trie> children;
private boolean isNode;
private T value;
public Trie() {
children = new HashMap<Character, Trie>();
isNode = false;
value = null;
}
public void insert(String key, T value) {
Trie<T> current = this;
for (int i = 0; i < key.length(); i++) {
char c = key.charAt(i);
if (current.children.containsKey(c)) {
current = current.children.get(c);
} else {
Trie<T> next = new Trie();
current.children.put(c, next);
current = next;
}
}
current.isNode = true;
current.value = value;
}
public List<T> get(String key) {
List<T> result = new ArrayList<T>();
get(this, key.toCharArray(), 0, result);
return result;
}
private void get(Trie<T> trie, char[] chars, int index, List<T> result) {
if (index == chars.length) {
if (trie != null && trie.isNode) {
result.add(trie.value);
}
return;
}
char c = chars[index];
if (trie.children.containsKey(c)) {
get(trie.children.get(c), chars, index + 1, result);
}
if (trie.children.containsKey(WILD)) {
get(trie.children.get(WILD), chars, index + 1, result);
}
}
}
public static void main(String[] args) {
Trie<Integer> trie = new Trie<Integer>();
trie.insert("00x1", 0);
trie.insert("01xx", 1);
trie.insert("100x", 2);
trie.insert("1010", 3);
trie.insert("1x11", 4);
System.out.println(trie.get("0110")); // [1]
System.out.println(trie.get("1011")); // [4]
}
}
答案 1 :(得分:2)
您可以在此处构建一个与字符串长度成线性匹配的自动机。例如,你可以在(减少的,有序的)binary decision diagram中存储字符串集 - 或者实际上是字符串上的函数。我怀疑任何一组字符串的BDD都会在符号总数中具有线性大小,但我没有证据。
BDD解决方案与Qiang Jin的优秀解决方案类似,但略有不同,其中构造肯定需要线性空间,但在最坏的情况下查询对我来说并不明显(对我而言)。
答案 2 :(得分:1)
我认为,模式容器的解决方案将是一个特定的有序树。
该节点中的匹配不应该由叶子完成,而是由级别完成。一个级别将是一个父母的子集。
Take first level of the children as current level
Take the first child on the level for current
read currentnode.position
check the appropriate position in the matched string against child value.
If it fits, go higher up the tree.
If it doesn't fit, go to next child.
If we are out of children on the level, go down the tree.
模式添加和二进制字符串匹配的复杂性在这里是log(n)。 如果有x%的x',则时间会缩短约为%,与@Qiang Jin的解决方案相反。搜索多分支树比仅仅三分支树更快。
我会将该树实现为列表层次结构。
答案 3 :(得分:0)
如果x模式的总数相对较小,你可以保留它们的列表,并使用哈希表来解决密钥中所有x都设置为1的元素(或者零,无关紧要)
然后查找查询及其所有修改后的表单,即根据x模式更改某些查询位的位置。 (如示例所示,也许可以检查哪些x模式会修改查询效率。)
举个例子:
index abcd hash-key x-patterns
0 00x1 => 0011 0010
1 01xx => 0111 0011
2 100x => 1001 0001
3 1010 => 1010 N/A
4 1x11 => 1111 0100
To match 0110, the first x-pattern does not modify 0110; 0111 matches index 1.
To match 1011, the first 3 x-patterns do not modify 1011; 1111 matches index 4.
JavaScript代码:
var hash = {3: 0, 7: 1, 9: 2, 10: 3, 15: 4}
, x_patterns = [2,3,1,4]
function lookup(query){
var mask = query ^ (Math.pow(2,31) - 1)
if (hash[query]){
return hash[query]
} else {
var i = 0
while (x_patterns[i]){
if (mask & x_patterns[i])
if (hash[query | x_patterns[i]])
return hash[query | x_patterns[i]]
i++
}
return false
}
}
console.log(lookup(11), lookup(6))
输出:
4 1
答案 4 :(得分:0)
我可以考虑一个快速而简单的解决方案,
首先,它的“不关心”的数量很少,你可以简单地扩展索引并使用常规哈希(python dict,C ++ map等),在这种情况下:
index abcd
0 00x1
成为这个:
index abcd
0 0001
1 0011
对索引的搜索是最快的。
希望它有所帮助!