从算法上讲,这可能不是最有效的解决方案,但从类设计的角度来看,它是干净的。该解决方案采用比较“排序”给定单词的方法。
如果一个单词包含相同数字中的相同字母,我们可以说它是另一个单词的排列。这意味着您可以将单词从 a 转换String
为 a Map<Character,Integer>
。这种转换将具有复杂性 O(n),其中 n 是 的长度String
,假设您的Map
实现中的插入成本为 O(1)。
它将包含在单词中找到的所有字符作为键,Map
并将字符的频率作为值。
例子。abbc 转换为[a->1, b->2, c->1]
bacb 转换为[a->1, b->2, c->1]
因此,如果您必须知道两个单词是否是另一个单词的排列,您可以将它们都转换为映射,然后调用Map.equals
.
然后,您必须遍历文本字符串并将转换应用于您要查找的单词长度相同的所有子字符串。
Inerdial 提出的改进
这种方法可以通过以“滚动”方式更新地图来改进。
即,如果您在i=3
OP 中的示例 haystack 中的索引处匹配(子字符串xya
),则地图将为[a->1, x->1, y->1]
. 在大海捞针中前进时,减少 的字符数haystack[i]
,增加 的字符数haystack[i+needle.length()]
。
(删除零以确保Map.equals()
有效,或者只是实现自定义比较。)
Max 提出的改进
如果我们也引入matchedCharactersCnt
变量呢?在干草堆的开始它将是0
。每次您将地图更改为所需值时 - 您都会增加变量。每次您将其更改为偏离所需值时 - 您都会减少变量。每次迭代检查变量是否等于针的长度。如果是 - 您已经找到了匹配项。它会比每次比较完整的地图要快。
Max提供的伪代码:
needle = "abbc"
text = "abbcbbabbcaabbca"
needleSize = needle.length()
//Map of needle character counts
targetMap = [a->1, b->2, c->1]
matchedLength = 0
curMap = [a->0, b->0, c->0]
//Initial map initialization
for (int i=0;i<needle.length();i++) {
if (curMap.contains(haystack[i])) {
matchedLength++
curMap[haystack[i]]++
}
}
if (matchedLength == needleSize) {
System.out.println("Match found at: 0");
}
//Search itself
for (int i=0;i<haystack.length()-needle.length();i++) {
int targetValue1 = targetMap[haystack[i]]; //Reading from hashmap, O(1)
int curValue1 = curMap[haystack[i]]; //Another read
//If we are removing beneficial character
if (targetValue1 > 0 && curValue1 > 0 && curValue1 <= targetValue1) {
matchedLength--;
}
curMap[haystack[i]] = curValue1 + 1; //Write to hashmap, O(1)
int targetValue2 = targetMap[haystack[i+needle.length()]] //Read
int curValue2 = curMap[haystack[i+needle.length()]] //Read
//We are adding a beneficial character
if (targetValue2 > 0 && curValue2 < targetValue2) { //If we don't need this letter at all, the amount of matched letters decreases
matchedLength++;
}
curMap[haystack[i+needle.length()]] = curValue2 + 1; //Write
if (matchedLength == needleSize) {
System.out.println("Match found at: "+(i+1));
}
}
//Basically with 4 reads and 2 writes which are
//independent of the size of the needle,
//we get to the maximal possible performance: O(n)