这让我想起了我曾经做过的一个变异的前缀树/树。略有不同,但它可能会起作用。如果您的界限很大/没有界限,或者您无法将其转换为您的语言(我用 C++ 编写代码),它可能不起作用。
所以基本上,在 trie 中,您通常存储与下一个字母相对应的孩子,但我所做的是存储与每个字母的频率相对应的孩子。
问题基本上是(从我的角度来看)是,“是否有任何集合具有与子集中相同或更多的字母?” 例如,如果子集是 { A,D,E,E },那么您需要查找是否存在至少包含一个 A、一个 D 和两个 E 的集合。
所以,对于 trie,你有这样的东西
Root
/ | \
/ /|\ \
/ / | \ \
1 2 ... MAX <-- This represents the frequency of "A"
/|\ ..... /|\
1..MAX 1..MAX <-- Frequency of "B"
...............
...............
...............
1 ... ... ... MAX <-- Frequency of "Y"
/|\ .... .... / | \
1..MAX ...... 1 .. MAX <-- Frequency of "Z"
基本上所有的……都代表了很多需要很长时间才能展示的东西。/,| 和\代表父子关系,MAX代表一个字母的最大频率
所以你要做的是,你有一个类似的结构(我用 c++ 编写代码):
struct NODE {
NODE *child[MAX + 1]; // Pointers to other NODE's that represents
// the frequency of the next letter
};
创建节点时,您需要将其所有子节点初始化为 NULL。您可以通过构造函数(在 C++ 中)或 makeNode() 函数(如
NODE* makeNode() {
NODE* n = new NODE; // Create a NODE
for(int i = 0;i <= MAX;i++) // For each child
n->child[i] = NULL; // Initialize to NULL
};
一开始,trie 只是一个根
NODE* root = new NODE;
当您将一组添加到 trie 时,您会获得每个字母的频率并通过 trie。如果在特定节点上,下一个字母对应的子节点为 NULL,则只需创建一个新节点。
当您搜索 trie 时,您搜索每个节点的所有子节点,这些子节点对应于子集中字母的频率或更大。例如,如果子集有 3 个 A,则搜索所有的 root->child[3] 然后 root->child[4] 然后 ... 然后 root->child[MAX]。
它可能过于复杂和令人困惑,所以 1)如果你认为我没有生气,那么请评论令人困惑的地方和 2)你可能/可能只想找到一个更简单的方法