Java 在不知道实际模式的情况下,如何检查字符串中重复出现的模式?

Java 在不知道实际模式的情况下,如何检查字符串中重复出现的模式?,java,string,string-parsing,Java,String,String Parsing,例如,我有一个字符串,“fbrtfuifigfbrt”。我想知道一个字符序列是否在字符串中重复出现,但我不知道这个字符序列是什么。在本例中,它是fbrt 我曾考虑过将字符串分解成一堆单独的单词,然后检查单词是否相同,但当解析较长的字符串时,这很快就会变得效率低下 现在,我实现了上述想法,但肯定有更好的想法 String s = "fbrtfuifigfbrt"; ArrayList<String> words = new ArrayList<String>(s.lengt

例如,我有一个字符串,“fbrtfuifigfbrt”。我想知道一个字符序列是否在字符串中重复出现,但我不知道这个字符序列是什么。在本例中,它是fbrt

我曾考虑过将字符串分解成一堆单独的单词,然后检查单词是否相同,但当解析较长的字符串时,这很快就会变得效率低下

现在,我实现了上述想法,但肯定有更好的想法

String s = "fbrtfuifigfbrt";
ArrayList<String> words = new ArrayList<String>(s.length() * s.length());

for(int outerLoop = 0; outerLoop <= s.length(); outerLoop++){
    for(int nestedLoop = 0; nestedLoop <= s.length(); nestedLoop++){
        words.add(fileContents.substring(outerLoop, nestedLoop));
    }
}
//I could dump the ArrayList in a HashSet and check if they are the same size, 
//then find those elements, etc. 
//but that goes along with the above code, and I would prefer to use a more efficient method
String s=“fbrtfuifigfbrt”;
ArrayList单词=新的ArrayList(s.length()*s.length());

对于(int-outerLoop=0;outerLoop您需要两个迭代器,第一个指针是整个字符串上的全局迭代器,第二个迭代器用作搜索指针。假设第一个迭代器指向示例中的字符“f”。我们需要找到全局迭代器后“f”的所有位置。对于每个“f”在全局迭代器之后发现,我们需要在全局迭代器和局部迭代器之后逐个比较字符(将其视为两个指针以相同的速度移动,直到它们指向不同的字符)。一旦局部迭代器到达字符串的末尾,就可以将全局迭代器向前移动一个字符(是的,如果字符串中有n个字符,则需要执行n次)

对不起,代码是C++的,但是java中的逻辑是相同的。< /P> 更新: 还有另一种执行此任务的方法。一种流行的解决方案是使用后缀树存储文本。然后,您可以搜索带有任何给定子字符串的后缀树,以查找整个文本中给定子字符串的出现情况。树的构建为O(n)搜索子字符串取决于字母表的大小,如果只使用英文字母,则字母表的大小为26。因此,如果要查找所有重复出现的模式,只需搜索给定文本的每个子字符串。这将是O(n^2)。因此,与我提出的算法相比,该算法具有整体优势。但是,如果您不需要性能,我的算法肯定会满足您的需要,因为它简单且易于实现

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, const char * argv[]) {
    string s = "sdfssdddfssss";
    int pairCount = 0;
    vector<string> rep;
    for (int i = 0; i < s.length(); i++)
    {
        vector<int> idx;
        //find all index of all same char as s[i] after i
        //Note: You can optimize this by creating a map of index of 26 letters.
        for (int j = i+1; j < s.length(); j++)
            if (s[i] == s[j]) idx.push_back(j);
        int offset = 0;
        for (int j = 0; j < idx.size(); j++)
        {
            while (s[i+offset] == s[idx[j]+offset])
            {
                cout << "Pair found! " << s.substr(i, offset+1) << " " << i << " " << idx[j] << " " << offset + 1 << endl;
                pairCount++;
                offset++;
            }
            offset = 0;
        }
    }
    cout << "Pair count: " << pairCount;
    return 0;
}
#包括
#包括
#包括
使用名称空间std;
int main(int argc,const char*argv[]{
字符串s=“sdfssdddfssss”;
int pairCount=0;
向量代表;
对于(int i=0;icout这方面没有很好的优化。你最终会得到某种蛮力解决方案

比如:

String myString = "abcabcbbb";
//for each char
for (int i = 0; i < myString.length(); i++) {
    //for each substring starting with that char
    int maxSubStringLen = Math.floorDiv(myString.length() - i, 2);
    for (int j = 1; j <= maxSubStringLen; j++) {
        //get the substring
        String subString = myString.substring(i, i + j);
        int repetitionIndex = i + j;
        String repetition = myString.substring(repetitionIndex, repetitionIndex + subString.length());

        //does the substring repeat?
        if (subString.equals(repetition)) {
            System.out.println(subString);
        }
    }
}
String myString=“abcabcbb”;
//对于每个字符
对于(int i=0;i对于(int j=1;jJava中的工作解决方案:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        String test1 = "fbrtfuifigfbrt";
        String test2 = "abcdabcd";
        String test3 = "fbrtxibrjkfbrt";
        System.out.println(findRepetitions(test1));
        System.out.println(findRepetitions(test2));
        System.out.println(findRepetitions(test3));
    }

    private static List<String> findRepetitions(String string) {
        List<String> patternsList = new ArrayList<>();
        int length = string.length();
        for (int i = 0; i < length; i++) { // search the first half
            int limit = (length - i) / 2; // candidates can't be longer than half the remaining length
            for (int j = 1; j <= limit; j++) {
                int candidateEndIndex = i + j;
                String candidate = string.substring(i, candidateEndIndex);
                if (string.substring(candidateEndIndex).contains(candidate)) {
                    patternsList.add(candidate);
                }
            }
        }
        return patternsList;
    }
}
正如其他人已经说过的,如果您不知道模式的长度或任何其他适用的限制,那么就不容易进行优化

如果您想天真地丢弃子模式,如
f
fb
fbr
,这些子模式只是因为它们是最长的
fbrt
模式的子字符串而被计数,那么您可以使
的内部
向下计数,从
限制
向下计数到1,这样您就可以先找到更长的模式,然后找到che在将下一个模式添加到列表之前,请检查下一个模式是否是已找到模式的子字符串。如下所示:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        String test1 = "fbrtfuifigfbrt";
        String test2 = "abcdabcd";
        String test3 = "fbrtxibrjkfbrt"; // "br" is a pattern but this version won't find it
        System.out.println(findRepetitions(test1));
        System.out.println(findRepetitions(test2));
        System.out.println(findRepetitions(test3));
    }

    private static List<String> findRepetitions(String string) {
        List<String> patternsList = new ArrayList<>();
        int length = string.length();
        for (int i = 0; i < length; i++) { // search the first half
            int limit = (length - i) / 2; // candidates can't be longer than half the remaining length
            for (int j = limit; j >= 1; j--) {
                int candidateEndIndex = i + j;
                String candidate = string.substring(i, candidateEndIndex);
                if (string.substring(candidateEndIndex).contains(candidate)) {
                    boolean notASubpattern = true;
                    for (String pattern : patternsList) {
                        if (pattern.contains(candidate)) {
                            notASubpattern = false;
                            break;
                        }
                    }
                    if (notASubpattern) {
                        patternsList.add(candidate);
                    }
                }
            }
        }
        return patternsList;
    }
}

当然,你可以包括更多的内部循环,以确保在实际丢弃候选字符串之前,不会在原始字符串中“单独”找到被丢弃的候选字符串……等等。这取决于你希望你的搜索有多积极。

需要更多关于什么符合条件的信息。字符串是否为“abcdabcdab”匹配一个模式?那么“xxabcabcx”如何?@nhouser9是的,两个模式的子字符串都符合条件(第一个模式为abc,第二个模式为abc)。模式必须出现多次才能成为模式。我认为您需要知道要创建的字符串的长度find@OscarMartinez我不知道子字符串的长度,因为它是可变的,可以是任何东西。因此对于字符串“aabbabcabaaaaa”,以下所有子字符串都将匹配:“a”、“b”、“ab”、“aa”、“aaa”.正确吗?如果您使用上述代码,您必须知道这是一个穷举搜索,这意味着它将为您提供所有可能的对,在最坏的情况下,此算法的复杂性为O(N^3)假设我有3个嵌套for循环。问题是用java来标记,java是C++。而C++的答案可能是程序员理解两种语言的一个例子,对于将来读者来说,找到一个java答案肯定是没有用的。不要像x_abcabc_x那样只在中间位置重复。像x_abc_efg_abc_x这样更远的重复不会被打印出来。但是,如果你用
索引替换第二个
子字符串
,它会起作用。
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        String test1 = "fbrtfuifigfbrt";
        String test2 = "abcdabcd";
        String test3 = "fbrtxibrjkfbrt"; // "br" is a pattern but this version won't find it
        System.out.println(findRepetitions(test1));
        System.out.println(findRepetitions(test2));
        System.out.println(findRepetitions(test3));
    }

    private static List<String> findRepetitions(String string) {
        List<String> patternsList = new ArrayList<>();
        int length = string.length();
        for (int i = 0; i < length; i++) { // search the first half
            int limit = (length - i) / 2; // candidates can't be longer than half the remaining length
            for (int j = limit; j >= 1; j--) {
                int candidateEndIndex = i + j;
                String candidate = string.substring(i, candidateEndIndex);
                if (string.substring(candidateEndIndex).contains(candidate)) {
                    boolean notASubpattern = true;
                    for (String pattern : patternsList) {
                        if (pattern.contains(candidate)) {
                            notASubpattern = false;
                            break;
                        }
                    }
                    if (notASubpattern) {
                        patternsList.add(candidate);
                    }
                }
            }
        }
        return patternsList;
    }
}
[fbrt, i]
[abcd]
[fbrt]