Java 检查干草堆是否包含针组的最快方法
我有一根草垛绳,我想检查它是否包含任何针绳。目前我是这样做的:Java 检查干草堆是否包含针组的最快方法,java,string,algorithm,pattern-matching,Java,String,Algorithm,Pattern Matching,我有一根草垛绳,我想检查它是否包含任何针绳。目前我是这样做的: Set<String> needles = ...; ... String [] pieces = haystack.split(" "); for (String piece: pieces) { if (needles.contains(piece) { return true; } } return false; 如果它真的是关于速度的,并且您希望搜索一个项目列表而不是一个固定的字符串,那么
Set<String> needles = ...;
...
String [] pieces = haystack.split(" ");
for (String piece: pieces) {
if (needles.contains(piece) {
return true;
}
}
return false;
如果它真的是关于速度的,并且您希望搜索一个项目列表而不是一个固定的字符串,那么您可以将工作划分为不同的线程(我不确定要检查多少个项目,但是如果不需要几分钟,这可能不是一种方法)
如果不需要将haystack生成一个数组,可以通过指针进行迭代,并通过String.contains()测试haystack 如果这一切都是关于速度的,并且您希望搜索一个项目列表而不是一个固定的字符串,那么您可以将工作划分为不同的线程(我不确定要检查多少个项目,但是如果不需要几分钟,这可能不是一种方法)
如果不需要将haystack生成一个数组,可以通过指针进行迭代,并通过String.contains()测试haystack 通常情况下,大多数减速都是split命令。搜索一个字符串比分配一大堆对象要好得多。您最好使用正则表达式,避免新的对象构造。使用Aho会非常有效。假设你的列表足够大而麻烦
public class NeedleFinder {
static final int RANGEPERMITTED = 26;
NeedleFinder next[];
public NeedleFinder() {
}
public NeedleFinder(String haystack) {
buildHaystack(haystack);
}
public void buildHaystack(String haystack) {
buildHaystack(this,haystack,0);
}
public void buildHaystack(NeedleFinder node, String haystack, int pos) {
if (pos >= haystack.length()) return;
char digit = (char) (haystack.charAt(pos) % RANGEPERMITTED);
if (digit == ' ') {
buildHaystack(this,haystack,pos+1);
return;
}
if (node.next == null) node.next = new NeedleFinder[RANGEPERMITTED];
if (node.next[digit] == null) node.next[digit] = new NeedleFinder();
NeedleFinder nodeNext = node.next[digit];
buildHaystack(nodeNext,haystack,pos+1);
}
public boolean findNeedle(String needle) {
return findNeedle(this, needle,0);
}
private boolean findNeedle(NeedleFinder node, String needle, int pos) {
if (pos >= needle.length()) return true;
char digit = (char) (needle.charAt(pos) % RANGEPERMITTED);
if (node.next == null) return false;
if (node.next[digit] == null) return false;
return findNeedle(node.next[digit],needle,pos+1);
}
}
如果成功,请检查包含的内容,以确保它不是假阳性。但是,它很快。我们说的是二进制搜索速度的五分之一
说到搜索,二进制搜索是个好主意。这是在正确的时间复杂性单独。只需对你愚蠢的草堆字符串列表进行排序,然后当你查看指针时进行二进制搜索。在java中,这些是集合中的基本项。.sort()和.binarySearch()命令。这将是一个数量级的好比野蛮
value = Collections.binarySearch(haystackList, needle, strcomp);
如果该值为正值,则已找到该值
Collections.sort(words, strcomp);
用strcomp
public Comparator<String> strcomp = new Comparator<String>() {
@Override
public int compare(String s, String t1) {
if ((s == null) && (t1 == null)) return 0;
if (s == null) return 1;
if (t1 == null) return -1;
return s.compareTo(t1);
}
};
公共比较器strcomp=新比较器(){
@凌驾
公共整数比较(字符串s、字符串t1){
if((s==null)和&(t1==null))返回0;
如果(s==null)返回1;
if(t1==null)返回-1;
返回s.compareTo(t1);
}
};
一般来说,大多数减速都是split命令。搜索一个字符串比分配一大堆对象要好得多。您最好使用正则表达式,避免新的对象构造。使用Aho会非常有效。假设你的列表足够大而麻烦
public class NeedleFinder {
static final int RANGEPERMITTED = 26;
NeedleFinder next[];
public NeedleFinder() {
}
public NeedleFinder(String haystack) {
buildHaystack(haystack);
}
public void buildHaystack(String haystack) {
buildHaystack(this,haystack,0);
}
public void buildHaystack(NeedleFinder node, String haystack, int pos) {
if (pos >= haystack.length()) return;
char digit = (char) (haystack.charAt(pos) % RANGEPERMITTED);
if (digit == ' ') {
buildHaystack(this,haystack,pos+1);
return;
}
if (node.next == null) node.next = new NeedleFinder[RANGEPERMITTED];
if (node.next[digit] == null) node.next[digit] = new NeedleFinder();
NeedleFinder nodeNext = node.next[digit];
buildHaystack(nodeNext,haystack,pos+1);
}
public boolean findNeedle(String needle) {
return findNeedle(this, needle,0);
}
private boolean findNeedle(NeedleFinder node, String needle, int pos) {
if (pos >= needle.length()) return true;
char digit = (char) (needle.charAt(pos) % RANGEPERMITTED);
if (node.next == null) return false;
if (node.next[digit] == null) return false;
return findNeedle(node.next[digit],needle,pos+1);
}
}
如果成功,请检查包含的内容,以确保它不是假阳性。但是,它很快。我们说的是二进制搜索速度的五分之一
说到搜索,二进制搜索是个好主意。这是在正确的时间复杂性单独。只需对你愚蠢的草堆字符串列表进行排序,然后当你查看指针时进行二进制搜索。在java中,这些是集合中的基本项。.sort()和.binarySearch()命令。这将是一个数量级的好比野蛮
value = Collections.binarySearch(haystackList, needle, strcomp);
如果该值为正值,则已找到该值
Collections.sort(words, strcomp);
用strcomp
public Comparator<String> strcomp = new Comparator<String>() {
@Override
public int compare(String s, String t1) {
if ((s == null) && (t1 == null)) return 0;
if (s == null) return 1;
if (t1 == null) return -1;
return s.compareTo(t1);
}
};
公共比较器strcomp=新比较器(){
@凌驾
公共整数比较(字符串s、字符串t1){
if((s==null)和&(t1==null))返回0;
如果(s==null)返回1;
if(t1==null)返回-1;
返回s.compareTo(t1);
}
};
您应该看看算法。这适合您的问题,因为它构建了一个包含所有单词(针)的自动机,并在构建的自动机上遍历文本(草堆)以查找所有匹配的单词。它基本上构造了一个类似于trie的有限状态机
时间复杂度为O(n+m+z)
z
是文本中出现的单词总数,n
是文本长度,m
是所有单词中的字符总数
编辑2
这是一个直接的实现,在找到任何针的第一次出现后停止遍历
import java.util.*;
class AhoCorasick {
static final int ALPHABET_SIZE = 256;
Node[] nodes;
int nodeCount;
public static class Node {
int parent;
char charFromParent;
int suffLink = -1;
int[] children = new int[ALPHABET_SIZE];
int[] transitions = new int[ALPHABET_SIZE];
boolean leaf;
{
Arrays.fill(children, -1);
Arrays.fill(transitions, -1);
}
}
public AhoCorasick(int maxNodes) {
nodes = new Node[maxNodes];
// create root
nodes[0] = new Node();
nodes[0].suffLink = 0;
nodes[0].parent = -1;
nodeCount = 1;
}
public void addString(String s) {
int cur = 0;
for (char ch : s.toCharArray()) {
int c = ch;
if (nodes[cur].children[c] == -1) {
nodes[nodeCount] = new Node();
nodes[nodeCount].parent = cur;
nodes[nodeCount].charFromParent = ch;
nodes[cur].children[c] = nodeCount++;
}
cur = nodes[cur].children[c];
}
nodes[cur].leaf = true;
}
public int suffLink(int nodeIndex) {
Node node = nodes[nodeIndex];
if (node.suffLink == -1)
node.suffLink = node.parent == 0 ? 0 : transition(suffLink(node.parent), node.charFromParent);
return node.suffLink;
}
public int transition(int nodeIndex, char ch) {
int c = ch;
Node node = nodes[nodeIndex];
if (node.transitions[c] == -1)
node.transitions[c] = node.children[c] != -1 ? node.children[c] : (nodeIndex == 0 ? 0 : transition(suffLink(nodeIndex), ch));
return node.transitions[c];
}
// Usage example
public static void main(String[] args) {
AhoCorasick ahoCorasick = new AhoCorasick(1000);
ahoCorasick.addString("big");
ahoCorasick.addString("tasty");
String s = "I am a big tasty potato";
int node = 0;
for (int i = 0; i < s.length(); i++) {
node = ahoCorasick.transition(node, s.charAt(i));
if (ahoCorasick.nodes[node].leaf) {
System.out.println("A match found! Needle ends at: " + i); // A match found! Needle ends at: 9
break;
}
}
}
}
import java.util.*;
职业病{
静态最终整数字母表大小=256;
节点[]节点;
int nodeCount;
公共静态类节点{
int父代;
来自父代的字符;
int suffLink=-1;
int[]children=新int[字母表大小];
int[]转换=新int[字母表大小];
布尔叶;
{
数组。填充(子级,-1);
数组。填充(转换,-1);
}
}
公共节点(int-maxNodes){
节点=新节点[maxNodes];
//创建根
节点[0]=新节点();
节点[0]。suffLink=0;
节点[0]。父节点=-1;
nodeCount=1;
}
公共void addString(字符串s){
int cur=0;
for(char ch:s.toCharArray()){
int c=ch;
if(节点[cur].子节点[c]=-1){
节点[nodeCount]=新节点();
节点[nodeCount]。父节点=cur;
节点[nodeCount].charFromParent=ch;
节点[cur].子节点[c]=nodeCount++;
}
cur=节点[cur]。子节点[c];
}
节点[cur].leaf=true;
}
公共内部链接(内部节点索引){
节点=节点[nodeIndex];
如果(node.suffLink==-1)
node.suffLink=node.parent==0?0:转换(suffLink(node.parent)、node.charFromParent);
返回node.suffLink;
}
公共int转换(int nodeIndex,char ch){
int c=ch;
节点=节点[nodeIndex];
if(节点转换[c]=-1)
node.transitions[c]=node.children[c]!=-1?node.children[c]:(nodeIndex==0?0:transition(suffLink(nodeIndex),ch));
返回node.transitions[c];
}
//用法示例
公共静态void main(字符串[]args){
ahocarasick ahocarasick=新ahocarasick(1000);
ahocarasick.addString(“大”);
ahocarasick.addString(“美味”);
String s=“我是一个美味的大土豆”;
int节点=0;
对于(int i=0;i