最近在一次采访中有人问我这个问题:
给出输入字符串,检查它是否具有重复模式并返回true或false。例如:
的重复模式"abbaabbaabbaabba"
是"abba"
private boolean checkPattern(String input) {
}
我们如何使用正则表达式以及不使用正则表达式来解决它?我对使用正则表达式和不使用正则表达式的方法都感兴趣。
答案 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 - 模式的长度。