我在暑期实习的电话采访中被问到这个问题,并试图在Java中提出一个非常复杂的解决方案(虽然它也不准确)。
我有一个带2个字符串的函数,假设是“common”和“cmn”。它应该基于“c”,“m”,“n”在“common”中以相同顺序发生的事实返回True。但是如果参数是“共同的”和“omn”,它将返回False,因为即使它们以相同的顺序发生,但是'm'也出现在'o'之后(它没有模式匹配条件)
我使用Hashmaps和Ascii数组已经完成了它,但还没有得到令人信服的解决方案!从我读到现在,它可以与Boyer-Moore或Levenshtein距离算法有关吗?
希望在stackoverflow上暂时休息! :)
编辑:有些答案谈论减少字长或创建哈希集。但根据我的理解,这个问题不能用hashsets来完成,因为第一个字符串中每个字符的出现/重复都有其自身的意义。通过条件 - “con”,“cmn”,“cm”,“cn”,“mn”,“on”,“co”。失败的条件可能看起来不是 - “com”,“omn”,“mon”,“om”。这些是FALSE / FAIL,因为“o”发生在“m”之前和之后。另一个例子 - “google”,“ole”会PASS,但“google”,“gol”会失败,因为“o”也出现在“g”之前!
答案 0 :(得分:4)
我认为这很简单。运行模式,然后每个字符获取它在字符串中最后一次出现的索引。索引必须始终增加,否则返回false。 所以在伪代码中:
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
进行比较,算法会更快。
更新:修正了算法中的错误。添加附加条件以考虑模式中字母的顺序。
答案 1 :(得分:2)
一个很好的问题和几个小时的研究,我想我找到了解决方案。首先让我尝试用不同的方法解释这个问题。
<强>要求:强>
让我们考虑相同的例子'common'(mainString)和'cmn'(subString)。首先我们需要清楚的是,任何字符都可以在mainString和subString中重复,并且由于我们专注于它的模式,角色的索引起着重要的作用。所以我们需要知道:
让我们保持这种状态并继续检查模式。对于common这个词,我们需要找出特定模式cmn是否存在。可能的共同点是: - (优先权适用)
在任何时候,此优先级和比较必须有效。由于优先级起着重要作用,我们需要拥有每个唯一字符的索引而不是存储不同的模式。
<强>解决方案强>
解决方案的第一部分是使用以下标准创建哈希表: -
模式匹配的第二个主要部分: -
在循环增量之前,验证两个条件
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
显示标志
N.B:由于我在Java方面不是那么多才多艺,所以我没有提交代码。但有些人可以尝试实现我的想法
答案 2 :(得分:1)
我自己以低效的方式完成了这个问题,但确实给出了准确的结果!如果有人能从中找到一个有效的代码/算法,我将不胜感激!
创建一个函数“Check”,它将2个字符串作为参数。检查字符串1中字符串2的每个字符.S1中每个字符的出现顺序应在S1中验证为真。
可以看出,这是一种强力方法......我猜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;
}
}
答案 3 :(得分:0)
O(n log n)不可行吗?
步骤1,通过消除右侧显示的所有字符来减少字符串。严格来说,如果字符出现在您正在检查的字符串中,则只需要消除字符。
/** 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();
}
步骤2,检查遏制。
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距离对你不会有帮助,因为它有一个属性,如果你交换参数输出是相同的,但你想要的算法不会。
答案 4 :(得分:0)
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
答案 5 :(得分:0)
我认为这是我编写过的最糟糕的代码之一,或者是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
答案 6 :(得分:0)
我认为这不是对您的计算机科学基础的测试,更多的是您在Java编程环境中的实际操作。
你可能在第二个参数中构建正则表达式,即......
omn -> o.*m[^o]*n
...然后使用String.matches(...)或使用Pattern类测试候选字符串。
在通用形式中,RegExp的构造应遵循以下几行。
exp - &gt; in [0] 。* + for each x:2 - &gt; in.lenght {( in [x-1] + [^ [x-2]] * + [strong> in [x] )}
例如:
demmn - &gt; d。* E [^ d] *米[^ E] * M [^ M] * N
答案 7 :(得分:0)
我以不同的方式尝试自己。只是分享我的解决方案。
公共类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);
}
}