index = -1
foreach c in pattern
checkindex = string.lastIndexOf(c)
if checkindex == -1 //not found
return false
if checkindex < index
return false
if string.firstIndexOf(c) < index //characters in the wrong order
return false
index = checkindex
return true
编辑:你可以通过将index
作为lastIndexOf
方法的起始索引来进一步改进代码。那么,您就不必将checkindex
与index
进行比较,算法将更快。
更新:修复了算法中的一个错误。添加了额外条件以考虑模式中字母的顺序。
pattern
是字符串 "cmn",string
是 "common"。但是您是正确的,我的算法会错误地返回模式 "mon" 的 true。但是这可以通过添加一个额外的检查来轻松解决,即当前模式字符是否也出现在较低的索引处。我将相应地编辑我的答案。 - raymiJust before loop increment, verify two conditions
If highestIndex(current character) > highestIndex(next character) Then
Pattern Fails, Flag <- False, Terminate Loop
// This condition is applicable for almost all the cases for pattern matching
Else If lowestIndex(current character) > lowestIndex(next character) Then
Pattern Fails, Flag <- False, Terminate Loop
// This case is explicitly for cases in which patterns like 'mon' appear
Display the Flag
注意:由于我对Java不是很熟悉,所以没有提交代码。但是有人可以尝试实现我的想法。
我自己用了一种低效的方法来解决这个问题,但它确实给出了准确的结果!如果有人能从中找出一种高效的代码/算法,我将不胜感激!
创建一个名为“Check”的函数,它接受两个字符串作为参数。检查字符串2的每个字符在字符串1中的出现顺序是否正确。
可以看出,这是一种暴力方法......我猜时间复杂度是O(N^3)
public class Interview
{
public static void main(String[] args)
{
if (check("google", "oge"))
System.out.println("yes");
else System.out.println("sorry!");
}
public static boolean check (String s, String p)
{
int[] asciiArr = new int[256];
for(int pIndex=0; pIndex<p.length(); pIndex++) //Loop1 inside p
{
for(int sIndex=0; sIndex<s.length(); sIndex++) //Loop2 inside s
{
if(p.charAt(pIndex) == s.charAt(sIndex))
{
asciiArr[s.charAt(sIndex)] = sIndex; //adding char from s to its Ascii value
for(int ascIndex=0; ascIndex<256; ) //Loop 3 for Ascii Array
{
if(asciiArr[ascIndex]>sIndex) //condition to check repetition
return false;
else ascIndex++;
}
}
}
}
return true;
}
}
这不是可以在O(n log n)的时间复杂度内完成吗?
第一步,通过消除所有出现在右侧的字符来缩小字符串。严格来说,你只需要在检查的字符串中消除字符。
/** Reduces the maximal subsequence of characters in container that contains no
* character from container that appears to the left of the same character in
* container. E.g. "common" -> "cmon", and "whirlygig" -> "whrlyig".
*/
static String reduceContainer(String container) {
SparseVector charsToRight = new SparseVector(); // Like a Bitfield but sparse.
StringBuilder reduced = new StringBuilder();
for (int i = container.length(); --i >= 0;) {
char ch = container.charAt(i);
if (charsToRight.add(ch)) {
reduced.append(ch);
}
}
return reduced.reverse().toString();
}
第二步,检查包含关系。
static boolean containsInOrder(String container, String containee) {
int containerIdx = 0, containeeIdx = 0;
int containerLen = container.length(), containeeLen == containee.length();
while (containerIdx < containerLen && containeeIdx < containeeLen) {
// Could loop over codepoints instead of code-units, but you get the point...
if (container.charAt(containerIdx) == containee.charAt(containeeIdx)) {
++containeeIdx;
}
++containerIdx;
}
return containeeIdx == containeeLen;
}
回答你的第二个问题,Levenshtein距离不会对你有所帮助,因为它具有这样的属性:如果你交换参数,输出结果是相同的,但是你想要的算法却不是这样的。
containsInOrder("common", "omn")=true
。 - RonK我用了另一种方法尝试了一下,现在分享我的解决方案。
public class PatternMatch {
public static boolean matchPattern(String str, String pat) {
int slen = str.length();
int plen = pat.length();
int prevInd = -1, curInd;
int count = 0;
for (int i = 0; i < slen; i++) {
curInd = pat.indexOf(str.charAt(i));
if (curInd != -1) {
if(prevInd == curInd)
continue;
else if(curInd == (prevInd+1))
count++;
else if(curInd == 0)
count = 1;
else count = 0;
prevInd = curInd;
}
if(count == plen)
return true;
}
return false;
}
public static void main(String[] args) {
boolean r = matchPattern("common", "on");
System.out.println(r);
}
}
public class StringPattern {
public static void main(String[] args) {
String inputContainer = "common";
String inputContainees[] = { "cmn", "omn" };
for (String containee : inputContainees)
System.out.println(inputContainer + " " + containee + " "
+ containsCommonCharsInOrder(inputContainer, containee));
}
static boolean containsCommonCharsInOrder(String container, String containee) {
Set<Character> containerSet = new LinkedHashSet<Character>() {
// To rearrange the order
@Override
public boolean add(Character arg0) {
if (this.contains(arg0))
this.remove(arg0);
return super.add(arg0);
}
};
addAllPrimitiveCharsToSet(containerSet, container.toCharArray());
Set<Character> containeeSet = new LinkedHashSet<Character>();
addAllPrimitiveCharsToSet(containeeSet, containee.toCharArray());
// retains the common chars in order
containerSet.retainAll(containeeSet);
return containerSet.toString().equals(containeeSet.toString());
}
static void addAllPrimitiveCharsToSet(Set<Character> set, char[] arr) {
for (char ch : arr)
set.add(ch);
}
}
输出:
common cmn true
common omn false
我认为这是我曾经编写过的最糟糕的代码之一,或者是stackoverflow上最糟糕的代码示例之一...但是你知道吗...所有的条件都得到了满足!
没有算法能真正满足需求,所以我只使用了暴力方法...试试看...
而且我对空间和时间复杂度并不在意...我的目标首先是尝试解决它...也许以后再改进它!
public class SubString {
public static void main(String[] args) {
SubString ss = new SubString();
String[] trueconditions = {"con", "cmn", "cm", "cn", "mn", "on", "co" };
String[] falseconditions = {"com", "omn", "mon", "om"};
System.out.println("True Conditions : ");
for (String str : trueconditions) {
System.out.println("SubString? : " + str + " : " + ss.test("common", str));
}
System.out.println("False Conditions : ");
for (String str : falseconditions) {
System.out.println("SubString? : " + str + " : " + ss.test("common", str));
}
System.out.println("SubString? : ole : " + ss.test("google", "ole"));
System.out.println("SubString? : gol : " + ss.test("google", "gol"));
}
public boolean test(String original, String match) {
char[] original_array = original.toCharArray();
char[] match_array = match.toCharArray();
int[] value = new int[match_array.length];
int index = 0;
for (int i = 0; i < match_array.length; i++) {
for (int j = index; j < original_array.length; j++) {
if (original_array[j] != original_array[j == 0 ? j : j-1] && contains(match.substring(0, i), original_array[j])) {
value[i] = 2;
} else {
if (match_array[i] == original_array[j]) {
if (value[i] == 0) {
if (contains(original.substring(0, j == 0 ? j : j-1), match_array[i])) {
value[i] = 2;
} else {
value[i] = 1;
}
}
index = j + 1;
}
}
}
}
for (int b : value) {
if (b != 1) {
return false;
}
}
return true;
}
public boolean contains(String subStr, char ch) {
for (char c : subStr.toCharArray()) {
if (ch == c) {
return true;
}
}
return false;
}
}
-IvarD
我认为这不是对你的计算机科学基础知识的测试,而更多地涉及到你在Java编程环境中实际操作的能力。
你可以将第二个参数构建成一个正则表达式,例如...
omn -> o.*m[^o]*n
...然后通过使用String.matches(...)或使用Pattern类来测试候选字符串。
通用形式下,RegExp的构造应该沿着以下方向进行。
exp -> in[0].* + 对于每个x:2 -> in.lenght { (in[x-1] + [^in[x-2]]* + in[x]) }
例如:
demmn -> d.*e[^d]*m[^e]*m[^m]*n
.*m.*o.*n.*
不会)。但是可能可以通过更复杂的正则表达式来解决,其中你将.
替换为“前面或后面的模式字符或不在模式中的任何字符”。所以类似于[^on]*m[^n]*o[^m]*n[^mo]*
这样的东西(我不是一个正则表达式专家)。 - raymi[^e]
将变成类似于[^den]
。然后,你还必须在模式的开头和结尾添加表达式。这将让你得到像这样的东西(针对你的例子):[^emn]*d[^mn]*e[^dn]*m[^den]*m[^de]*n[^dem]*
。 - raymi
como
会匹配,但cmo
不会,您能解释一下匹配的规则是什么吗? - RonKomn
中,如果字符串中出现了字母m
排在字母o
后面,那么这个字符串就不符合该模式的匹配条件。需要提供一个更准确的匹配条件描述,以便理解这个模式。 - AnT stands with Russia