- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设我有一组 D
的多重集:
D = {
{d, g, o},
{a, e, t, t},
{a, m, t},
}
给定一个多重集M
,比如
M = {a, a, m, t}
我想要一个算法 f
为我提供 D
的所有元素,这些元素是 M
的子集(或更准确地说,“submultisets”) >:
f = {{a, m, t}}
如果我们只做一个这样的查询,扫描 D
的所有元素(在 O(#D)
时间内)显然是最优的。但是如果我们想回答许多针对相同 D
和不同 M
的查询,我们可以通过将 D
预处理为一些更智能的数据结构。
我们可以将所有 D
放入哈希表中,并遍历 M
的所有可能子集,在哈希表中查找每个子集,但那是 O(2 ^#M)
。适合小型 M
,不适合中到大型 M
。
在 #M
中是否可以在多项式时间内完成此操作?或者也许将一个已知的 NP 完全问题简化为这个问题,以证明不可能很快?
编辑:我刚刚意识到在最坏的情况下,我们需要输出所有的D
,所以#D
仍然会出现在时间复杂度上。因此,让我们假设输出的大小受某个常数的限制。
最佳答案
这是 TernarySearchTree (TST) 的快速实现,可以帮助您解决问题。多年前,我受到 DrDobbs 上一篇文章的启发。您可以在 http://www.drdobbs.com/database/ternary-search-trees/184410528 阅读更多相关信息。 .它提供了一些有关 TST 和性能分析的背景。
在您的问题描述示例中,D 将是包含“dgo”、“aett”和“amt”键的字典。值与键相同。
M 是您的搜索字符串,基本上是说“给我字典中的所有值,键包含这些字母的子集或所有”。字符的顺序并不重要。人物 '。'在搜索中用作通配符。
对于任何给定的 M,此算法和数据结构不需要您查看 D 的所有元素。因此在这方面它会很快。我也对访问的节点数做了一些测试,大多数时候,访问的节点数只是字典中总节点数的一小部分,即使对于找不到的键也是如此。
此算法还允许您输入最小和最大长度,以限制字典返回的键。
对于冗长的代码,我们深表歉意,但它已经完成,您可以进行测试。
import java.util.ArrayList;
import java.io.*;
public class TSTTree<T>
{
private TSTNode<T> root;
private int size = 0;
private int totalNodes = 0;
public int getSize() { return size; }
public int getTotalNodes() { return totalNodes; }
public TSTTree()
{
}
public TSTNode<T> getRoot() { return root; }
public void insert(String key, T value)
{
if(key==null || key.length()==0) return;
char[] keyArray = key.toCharArray();
if(root==null) root = new TSTNode<T>(keyArray[0]);
TSTNode<T> currentNode = root;
TSTNode<T> parentNode = null;
int d = 0;
int i = 0;
while(currentNode!=null)
{
parentNode = currentNode;
d = keyArray[i] - currentNode.getSplitChar();
if(d==0)
{
if((++i) == keyArray.length) // Found the key
{
if(currentNode.getValue()!=null)
System.out.println(currentNode.getValue() + " replaced with " + value);
else
size++;
currentNode.setValue(value); // Replace value at Node
return;
}
else
currentNode = currentNode.getEqChild();
}
else if(d<0)
currentNode = currentNode.getLoChild();
else
currentNode = currentNode.getHiChild();
}
currentNode = new TSTNode<T>(keyArray[i++]);
totalNodes++;
if(d==0)
parentNode.setEqChild(currentNode);
else if(d<0)
parentNode.setLoChild(currentNode);
else
parentNode.setHiChild(currentNode);
for(;i<keyArray.length;i++)
{
TSTNode<T> tempNode = new TSTNode<T>(keyArray[i]);
totalNodes++;
currentNode.setEqChild(tempNode);
currentNode = tempNode;
}
currentNode.setValue(value); // Insert value at Node
size++;
}
public ArrayList<T> find(String charsToSearch) {
return find(charsToSearch,1,charsToSearch.length());
}
// Return all values with keys between minLen and maxLen containing "charsToSearch".
public ArrayList<T> find(String charsToSearch, int minLen, int maxLen) {
ArrayList<T> list = new ArrayList<T>();
char[] charArray = charsToSearch.toCharArray();
int[] charFreq = new int[256];
for(int i=0;i<charArray.length;i++) charFreq[charArray[i]]++;
maxLen = charArray.length>maxLen ? maxLen : charArray.length;
pmsearch(root,charFreq,minLen,maxLen,1, list);
return list;
}
public void pmsearch(TSTNode<T> node, int[] charFreq, int minLen, int maxLen, int depth, ArrayList<T> list) {
if(node==null) return;
char c = node.getSplitChar();
if(isSmaller(charFreq,c))
pmsearch(node.getLoChild(),charFreq,minLen,maxLen,depth,list);
if(charFreq[c]>0) {
if(depth>=minLen && node.getValue()!=null) list.add(node.getValue());
if(depth<maxLen) {
charFreq[c]--;
pmsearch(node.getEqChild(),charFreq,minLen,maxLen,depth+1,list);
charFreq[c]++;
}
}
else if(charFreq['.']>0) { // Wildcard
if(depth>=minLen && node.getValue()!=null) list.add(node.getValue());
if(depth<maxLen) {
charFreq['.']--;
pmsearch(node.getEqChild(),charFreq,minLen,maxLen,depth+1,list);
charFreq['.']++;
}
}
if(isGreater(charFreq,c))
pmsearch(node.getHiChild(),charFreq,minLen,maxLen,depth,list);
}
private boolean isGreater(int[] charFreq, char c) {
if(charFreq['.']>0) return true;
boolean retval = false;
for(int i=c+1;i<charFreq.length;i++) {
if(charFreq[i]>0) {
retval = true;
break;
}
}
return retval;
}
private boolean isSmaller(int[] charFreq, char c) {
if(charFreq['.']>0) return true;
boolean retval = false;
for(int i=c-1;i>-1;i--) {
if(charFreq[i]>0) {
retval = true;
break;
}
}
return retval;
}
}
下面是一个小测试程序。测试程序只是按照确切的顺序在您的示例中插入 4 个键/值对。如果你有一个包含很多元素的 D,那么最好先对它进行排序,然后以锦标赛的方式构建字典(即插入中间元素,然后递归地填充左半部分和右半部分)。这将确保树是平衡的。
import org.junit.*;
import org.junit.runner.*;
import java.io.*;
import java.util.*;
import org.junit.runner.notification.Failure;
public class MyTest
{
static TSTTree<String> dictionary = new TSTTree<String>();
@BeforeClass
public static void initialize() {
dictionary.insert("dgo","dgo");
dictionary.insert("aett","aett");
dictionary.insert("amt","amt");
}
@Test
public void testMethod() {
System.out.println("testMethod");
ArrayList<String> result = dictionary.find("aamt");
System.out.println("Results: ");
for(Iterator it=result.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
@Test
// Test with a wildcard which finds "dgo" value
public void testMethod1() {
System.out.println("testMethod1");
ArrayList<String> result = dictionary.find("aamtdo.");
System.out.println("Results: ");
for(Iterator it=result.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
public static void main(String[] args) {
Result result = JUnitCore.runClasses(MyTest.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
}
}
关于algorithm - 如何找到给定集合中多重集合的所有子集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22223651/
例如,我有一个父类Author: class Author { String name static hasMany = [ fiction: Book,
代码如下: dojo.query(subNav.navClass).forEach(function(node, index, arr){ if(dojo.style(node, 'd
我有一个带有 Id 和姓名的学生表和一个带有 Id 和 friend Id 的 Friends 表。我想加入这两个表并找到学生的 friend 。 例如,Ashley 的 friend 是 Saman
我通过互联网浏览,但仍未找到问题的答案。应该很容易: class Parent { String name Child child } 当我有一个 child 对象时,如何获得它的 paren
我正在尝试创建一个以 Firebase 作为我的后端的社交应用。现在我正面临如何(在哪里?)找到 friend 功能的问题。 我有每个用户的邮件地址。 我可以访问用户的电话也预订。 在传统的后端中,我
我主要想澄清以下几点: 1。有人告诉我,在 iOS 5 及以下版本中,如果您使用 Game Center 设置多人游戏,则“查找 Facebook 好友”(如与好友争夺战)的功能不是内置的,因此您需要
关于redis docker镜像ENTRYPOINT脚本 docker-entrypoint.sh : #!/bin/sh set -e # first arg is `-f` or `--some-
我是一名优秀的程序员,十分优秀!