Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java indexOf(蛮力方法)对我或其他子字符串算法更实用吗?_Java_String_Algorithm_Substring - Fatal编程技术网

Java indexOf(蛮力方法)对我或其他子字符串算法更实用吗?

Java indexOf(蛮力方法)对我或其他子字符串算法更实用吗?,java,string,algorithm,substring,Java,String,Algorithm,Substring,我正在寻找在许多短文本行(haystack)中找到非常短的子字符串(模式、针)。然而,我不太确定除了天真、暴力的方法之外,应该使用哪种方法 背景:我正在做一个有趣的附带项目,在那里我收到多个用户的短信聊天日志(从2000-15000行文字到2-50个用户),我想根据我想到的预定单词在聊天日志中找到所有不同的模式匹配。到目前为止,我有大约1600个模式,我正在寻找,但我可能会寻找更多 例如,我想找出一般短信日志中使用的食品相关词语的数量,如“汉堡”、“比萨饼”、“可乐”、“午餐”、“晚餐”、“餐厅

我正在寻找在许多短文本行(haystack)中找到非常短的子字符串(模式、针)。然而,我不太确定除了天真、暴力的方法之外,应该使用哪种方法

背景:我正在做一个有趣的附带项目,在那里我收到多个用户的短信聊天日志(从2000-15000行文字到2-50个用户),我想根据我想到的预定单词在聊天日志中找到所有不同的模式匹配。到目前为止,我有大约1600个模式,我正在寻找,但我可能会寻找更多

例如,我想找出一般短信日志中使用的食品相关词语的数量,如“汉堡”、“比萨饼”、“可乐”、“午餐”、“晚餐”、“餐厅”、“麦当劳”。虽然我给出了英语示例,但实际上我的程序将使用韩语。每一个指定的单词都有各自的分数,我将其作为键和值分别放在hashmap中。然后,我展示了与食物相关的单词的得分最高的人,以及那些用户最常用的食物单词

我目前的方法是用空格消除每一行文本,并使用haystack包含模式的contains方法(使用indexOf方法和朴素的子字符串搜索算法)处理haystack中的每个单词

wordFromInput.contains(wordFromPattern);
举个例子,聊天室有17个用户,13000行文本,1600个模式,我发现使用这种方法整个程序需要12-13秒。而在我正在开发的Android应用程序上,它需要2分30秒来处理,这太慢了

最初,我尝试使用哈希映射,只获取模式,而不是在ArrayList中搜索它,但后来我意识到这是

对于我试图用一个子串做的事情

我在Stackoverflow中查找了很多有用的相关问题,例如以下两个:

和。我比较熟悉各种字符串算法(Boyer Moore、KMP等)

我最初认为,对于我的案例来说,naive方法当然是最糟糕的算法类型,但经过发现,我意识到我的案例(短模式,短文本)可能会更有效地使用naive方法。但我想知道是否有什么东西我完全忽略了

如果有人想更具体地看待我的问题,这里有一个建议

虽然我删除了大部分代码以简化它,但我用于实际匹配子字符串的主要方法存在于matchWords()方法中

我知道这是非常丑陋和糟糕的代码(5个循环…),所以如果有任何建议,我也很高兴听到它

因此,要清理它:

  • 聊天日志中的文字行(2000-10000+),haystack
  • 1600多个图案,针
  • 大部分使用韩文字符,但也包括一些英文字符
  • 蛮力天真的方法实在太慢了,但考虑到短模式和文本的性质,是否还有其他替代方法,即使有,它们是否实用,仍存在争议

我只想在我的思考过程中得到一些意见,可能还有一些一般性的建议。但是,另外,如果可能的话,我想对特定的算法或方法提出一些具体的建议。

我非常确定
string.contains
已经进行了高度优化,因此用其他方法替换它不会对您有多大好处

因此,我想,要做的不是在聊天词中查找每个银行词,而是一次进行多重比较


第一种方法是创建一个巨大的正则表达式来匹配所有银行单词。编译它,希望正则表达式包足够有效(很可能是这样)。您将有一个相当长的设置阶段(regex编译),但匹配应该快得多。

您可以为需要匹配的单词建立索引,并在处理它们时对它们进行计数。如果您可以使用HashMap来查找每个单词的模式,那么成本将是
O(n*m)

您可以对所有可能的单词使用HashMap,然后可以稍后对单词进行剖析

e、 假设你需要匹配红色和苹果,你可以将

redapple = 1
applered = 0
red = 10
apple = 15

这意味着红色实际上是11(10+1),苹果是16(15+1)

我不懂韩语,所以我想用韩语修补字符串的相同策略不一定像英语那样可行,但也许这个伪代码策略可以用你的韩语知识来实现。(Java当然还是一样的,但例如,在韩语中,字母“ough”很可能是连续的吗?甚至还有字母表示“ough”?但是,尽管如此,希望这一原则能够得到应用

我将使用String.ToCharray创建二维数组(如果需要可变大小,则使用ArrayList)

我建议跳到最后一个字母的原因是,从统计上看,一个单词的前两个字母的“辅音,元音”非常高,尤其是名词,因为任何食物都是名词(几乎你给出的所有关键字示例都与辅音,元音的结构相匹配)由于只有5个元音(加上y),第二个字母“i”出现在关键字“pizza”中的可能性很高,但在这一点之后,这个单词很有可能不匹配

然而,如果你知道第一个字母和最后一个字母匹配,那么你可能有一个更强的候选字母,然后可以反向迭代。我认为在更大的数据集上,这将比按顺序检查字母更快地消除候选字母。基本上,你会
if (first letter of word matches keyword's first letter)//we have a candidate
    skip to last letter of the current word //see comment below
    if(last letter of word matches keyword's last letter)//strong candidate
        iterate backwards to start+1 checking remainder of letters
private static class Matcher {
    private final int where;
    private final String s;
    private int i = 0;

    public Matcher ( String s, int where ) {
        this.s = s;
        this.where = where;
    }

    public boolean match(char ch) {
        return s.charAt(i++) == ch;
    }

    public int matched() {
        return i == s.length() ? where: -1;
    }
}

// Words I am looking for.
String[] watchFor = new String[] {"flies", "like", "arrow", "banana", "a"};
// Test string to search.
String test = "Time flies like an arrow, fruit flies like a banana";

public void test() {
    // Use a LinkedList because it is O(1) to remove anywhere.
    List<Matcher> matchers = new LinkedList<> ();
    int pos = 0;
    for ( char c : test.toCharArray()) {
        // Fire off all of the matchers at this point.
        for ( String s : watchFor ) {
            matchers.add(new Matcher(s, pos));
        }
        // Discard all matchers that fail here.
        for ( Iterator<Matcher> i = matchers.iterator(); i.hasNext(); ) {
            Matcher m = i.next();
            // Should it be removed?
            boolean remove = !m.match(c);
            if ( !remove ) {
                // Still matches! Is it complete?
                int matched = m.matched();
                if ( matched >= 0 ) {
                    // Todo - Should use getters.
                    System.out.println("    "+m.s +" found at "+m.where+" active matchers "+matchers.size());
                    // Complete!
                    remove = true;
                }
            }
            // Remove it where necessary.
            if ( remove ) {
                i.remove();
            }
        }
        // Step pos to keep track.
        pos += 1;
    }
}
flies found at 5 active matchers 6
like found at 11 active matchers 6
a found at 16 active matchers 2
a found at 19 active matchers 2
arrow found at 19 active matchers 6
flies found at 32 active matchers 6
like found at 38 active matchers 6
a found at 43 active matchers 2
a found at 46 active matchers 3
a found at 48 active matchers 3
banana found at 45 active matchers 6
a found at 50 active matchers 2
private Map<String, Set<Integer>> index; // pre-populated

Set<Integer> search(String... topics) {
    Set<Integer> results = null;
    for (String topic : topics) {
        Set<Integer> hits = index.get(topic);
        if (hits == null)
            return Collections.emptySet();
        if (results == null)
            results = new HashSet<Integer>(hits);
        else
            results.retainAll(hits);
        if (results.isEmpty())
            return Collections.emptySet(); // exit early
    }
    return results;
}