如何检查字符串是否具有重复模式?

时间:2019-04-25 03:32:35

标签: java regex algorithm

最近在一次采访中有人问我这个问题:

  

给出输入字符串,检查它是否具有重复模式并返回true或false。例如:   "abbaabbaabbaabba""abba"

的重复模式
private boolean checkPattern(String input) {

}

我们如何使用正则表达式以及不使用正则表达式来解决它?我对使用正则表达式和不使用正则表达式的方法都感兴趣。

8 个答案:

答案 0 :(得分:2)

没有正则表达式,您将不得不遍历每个可能的子字符串,该字符串的长度可以被原始字符串的长度整除,从原始字符串的索引0开始,然后检查是否重复。要检查它是否重复,您只需检查字符串中每pattern.length()个字符,以查看其是否为模式。例如,它看起来像这样,

public boolean checkPattern(String str) {
    String pattern = "";
    for (int i = 0; i < str.length()/2; i++) {
        pattern += str.charAt(i);
        if (str.length() % pattern.length() == 0 && isRepeating(str, pattern)) {
            return true;
        }
    }
    return false;
}

public boolean isRepeating(String str, String pattern) {
    String leftover = str;
    int currIndex = leftover.indexOf(pattern);
    while (currIndex == 0) {
        if(currIndex + pattern.length() == leftover.length()) {
            return true; // you have reached the last possible instance of the pattern at this point
        }
        leftover = leftover.substring(currIndex + pattern.length());
        currIndex = leftover.indexOf(pattern);
    }
    return false;
}

就像提到的用户thebjorn一样,仅在字符串的长度可除以模式的长度时,才可以调用isRepeating来防止对它们的不必要的调用,因此可以在if语句中进行模数检查。另外,模式可以在字符串中重复的最大长度为str.length()/2

答案 1 :(得分:2)

为此,我找到了使用正则表达式的解决方案。

诀窍是在非空的第一组上使用向后引用。

^(.+)(?:\1)+$

正如@PatrickParker指出的那样,如果您需要最小的重复模式,则可以使用惰性限定符

^(.+?)(?:\1)+$

答案 2 :(得分:1)

我不了解RegEx,所以我将以另一种方式来做。并且仅当String不是部分重复的字符串(即“ xbcabbaabbaabbaxx”)时才适用

首先,获取输入字符串,然后找到字符串大小的因数。质数表示没有重复模式,因为重复模式表示模式字符串长度的至少2的倍数。

感谢Tot Zam:Finding factors of a given integer

public ArrayList<Integer> findFactors(int num) {        
    ArrayList<Integer> factors = new ArrayList<Integer>();

    // Skip two if the number is odd
    int incrementer = num % 2 == 0 ? 1 : 2;

    for (int i = 1; i <= Math.sqrt(num); i += incrementer) {

        // If there is no remainder, then the number is a factor.
        if (num % i == 0) {
            factors.add(i);

            // Skip duplicates
            if (i != num / i) {
                factors.add(num / i);
            }

        }
    }

    // Sort the list of factors
    Collections.sort(factors);

    return factors;
}

找到数字的因数后,在您的情况下为16(结果为1,2,4,8,16),并且排除了最大因数(本身就是),您现在可以创建循环并迭代字符串的子字符串。您将每个值都与之前的值进行比较,然后使用“继续”进行检查,直到获得正确的值为止

例如,一个粗略的草图:

boolean isRepeatingPattern = false;
for (Integer factor : factors) {
    int iterations = stringSize / factor;
    String previousSubstring = stringParam.substring(0, factor); 
    for (int i = 1; i < iterations; i++) {
        int index = i * factor;
        if (previousSubstring != stringParam.substring(index, index + factor)) break;
        if (i == iterations - 1) repeatingPattern = true;
    }
}

答案 3 :(得分:0)

您可以将子字符串放入另一个变量中,并为初始字符串运行一个循环,以比较子字符串的第一个元素

如果匹配,则运行条件为子字符串。

如果子字符串中的任何前面的字符不匹配,请退出子字符串的if条件

答案 4 :(得分:0)

在所有位置创建带有所有子字符串的Trie。在添加时,如果您最终添加了一个单词两次(即该单词先前已添加),则表示它具有重复模式。

如果您希望图案长度大于任何长度,请更改代码以仅存储长度大于该长度的单词。或者单个字符也可以是重复模式。

答案 5 :(得分:0)

您可以使用String拆分方法来获取重复模式。

public static String getRepeatingPattern(String str) {
    String repeatingPattern =null;
    for(int i=0;i<str.length();i++) {
        repeatingPattern = str.substring(0, i+1);
        String[] ary = str.split(repeatingPattern);
        if(ary.length==0) {
            break;
        }
    }
 return repeatingPattern;
}

答案 6 :(得分:0)

我知道这篇文章过时了,但是它出现在有关该主题的google搜索的顶部,并且由于没有答案满足我的需要,我最终提出了一个可行的方法,我只是想将其添加到此帖子中,以供将来的搜索者使用。

此方法将生成找到的一个或多个模式,以及每个模式在原始字符串中重复的次数。

当我使用string.matches()尝试@flakes正则表达式时,只有模式并排时才匹配true。因此它会匹配101101而不匹配101234101(它似乎不知道模式101在其中两次。

因此,如果您只需要知道您的字符串并排是否具有相同的模式,请使用以下代码:

if (myString.matches("^(.+?)(?:\\1)+$")) {
  //doSomethingHere
}

我想到建立第n个模式的子字符串的想法,提出了这种方法,该方法基本上建立了所有可能模式的列表。然后遍历该列表并检查原始字符串以查看其中是否包含该模式。显然,它将忽略比较中的第一个匹配项,因为该模式将始终在源字符串中一次为true,这是由于从源字符串创建了该模式。

这是代码,显然您可以根据需要对其进行按摩:

private void checkForPattern(String userString) {
    String               buildString;
    LinkedList<String>   patterns    = new LinkedList<>();
    int                  size        = userString.length();
    int                  hits;
    int                  newSize;
    String[]             coreString  = new String[size];
    Map<String, Integer> hitCountMap = new HashMap<>();

    for (int x = 0; x < size; x++) {
        coreString[x] = userString.substring(x, x + 1);
    }

    for (int index = 0; index < size - 1; index++) {
        buildString = coreString[index];
        for (int x = index + 1; x < size; x++) {
            buildString = buildString + coreString[x];
            patterns.add(buildString);
        }
    }

    for (String pattern : patterns) {
        String check = userString.replaceFirst(pattern, "");
        if (check.contains(pattern)) {
            newSize = userString.replaceAll(pattern, "").length();
            hits    = (size - newSize) / pattern.length();
            hitCountMap.put(pattern, hits);
        }
    }

    for (String pattern : hitCountMap.keySet()) {
        System.out.println("Pattern: " + pattern +
                           " repeated " + hitCountMap.get(pattern) +
                           " times.");
    }
}

答案 7 :(得分:0)

private boolean checkPatternRepeatition(String s) {
    int secondMatch = (s + s).indexOf(s,1);
    return secondMatch < s.length();
}

每当字符串中存在模式重复时,将它们连接起来并搜索模式将导致索引小于字符串本身的长度。如果不是,它将返回字符串的长度。这需要 O(M^2) 时间复杂度,因为 indexOf() 时间复杂度是 O(M*N) 其中 M - 字符串的长度和 N - 模式的长度。

相关问题