假设我有一组单词,其中字符在a-z的集合中。我们还假设单词最多 10个字符,并且该集合可以由所有组合构建(没有排列,所以我不关心顺序)这些字符没有重复。数据库中的集合在开头是空的,有人必须填充它。我完全可以自由地构建数据库,以使其有效地进行此查询。让我们从一个例子开始。
有人通过插入以下单词来填充数据库:
"ab"
"ac"
"abcde"
"def"
"xyz"
现在我的子集就是这个:
"cabd"
我的查询/算法应该做的是,它应该返回“完成”排序的单词列表。为了更清楚,上面的查询应该按顺序返回这些单词:
"ab"
"ac"
"abcde"
"def"
"xyz"
我们来解释一下:
进一步观察:正如您所看到的,我不关心订单。如果我的子集查询是“abcd”,结果应该完全相同。
现在事情变得复杂了:每个单词都存储在DB中,ID作为主键。理想的解决方案应该是算法应该打印10个(或有限数量)ID,我将用它来查询我自己的单词。仅供参考,我正在使用Firebase,所以我现在不能依赖SQL
强力解决方案是在不同的表中存储char-word关系。所以要存储包含特定字符的所有单词id:
a : {
"id1",
"id2",
"id3",
"id4",
....
}
b : {
"id1",
"id4",
....
}
其中ID是:
id1 : {
"ab"
}
id2 : {
"ac"
}
id3 : {
"ad"
}
id4 : {
"abc"
}
正如您所看到的,使用此方法,算法将为我提供数千个查询和订购所需的结果,因此它不可扩展。有没有其他解决方案或智能方法来解决这个问题?
答案 0 :(得分:1)
最佳解决方案可能取决于您使用的SQL引擎,因为有些功能可以解决所需的一些步骤。
这是一个想法:
在带有单词的表格中,您可以添加一个整数列,该列将代表单词中出现的字母。一个整数有足够的位可用于在字母表中每个字母存储一位信息:1表示相应的字母出现,0表示它没有。因此,需要26位来表示a-z
范围内的字符。
然后,您可以在该表上创建一个触发器,以便只要在该表中插入新单词,就会计算并存储此整数。
然后,对于给定的输入字X,您还将计算该整数。要获得正确的顺序,您将对表中的每个整数执行此整数的按位OR,并计算结果中的1位。 1位越少,匹配越好。最少的1位数将对应于X的整数表示中的位数。在其上计数的每个位表示表行中不存在于X中的字符。
这是一个在MySql中设置它的脚本:
--/
create function bitset(str varchar(10)) returns int
begin
declare num int;
set num = 0;
while length(str) > 0 do
set num = num | power(2, ord(str) - ord('a'));
set str = substr(str, 2);
end while;
return num;
end
/
create table words (
word varchar(10),
bits int
);
create trigger ins_word before insert on words for each row
set new.bits = bitset(new.word);
insert into words(word) values ('ab'), ('ac'), ('abcde'), ('def'), ('xyz');
select word,
bits,
bit_count(bitset('cabd') | bits) bitwise_or
from words
order by 3;
最终查询使用自定义函数bitset
和MySql中的本机函数bit_count
。
最终查询的输出如下所示:
word | bits | bitwise_or
------+----------+-----------
ab | 3 | 4
ac | 5 | 4
abcde | 31 | 5
def | 56 | 6
xyz | 58720256 | 7