Я хотел опубликовать вариант, который будет более читабельным за счет некоторой производительности во время выполнения. Ответ Антона, вероятно, более производительный, но ИМХО менее читабельный, чем мог бы быть.
Хорошая особенность анаграмм заключается в том, что вы знаете их точную длину, и вы можете легко определить все возможные местоположения анаграмм. Для трехбуквенной анаграммы в стоге сена из 100 букв вы знаете, что существует 98 возможных мест:
- 0..2
- 1..3
- 2 ..4
- ...
- 96..98
- 97..99
Эти индексы могут быть сгенерированы довольно легко:
var amountOfPossibleAnagramLocations = haystack.Length - needle.Length + 1;
var substringIndexes = Enumerable.Range(0, amountOfPossibleAnagramLocations);
На этом этапе вы просто берете каждую указанную подстроку и проверяете, является ли она анаграммой.
var anagramLength = needle.Length;
int count = 0;
foreach(var index in substringIndexes)
{
var substring = haystack.Substring(index, anagramLength);
if(substring.IsAnagramOf(needle))
count++;
}
Обратите внимание, что многое из этого может быть сведено в одну цепочку LINQ:
var amountOfPossibleAnagramLocations = haystack.Length - needle.Length + 1;
var anagramLength = needle.Length;
var anagramCount = Enumerable
.Range(0, amountOfPossibleAnagramLocations)
.Select(x => haystack.Substring(x, anagramLength))
.Count(substring => substring.IsAnagramOf(needle));
Будет ли он более читабельным или нет, зависит от того, насколько вам удобно с LINQ. Я лично предпочитаю это (конечно, до разумного размера).
Чтобы проверить анаграмму, просто сортируйте символы и проверяйте равенство. Я использовал метод расширения для бонуса читабельности:
public static bool IsAnagramOf(this string word1, string word2)
{
var word1Sorted = String.Concat(word1.OrderBy(c => c));
var word2Sorted = String.Concat(word2.OrderBy(c => c));
return word1Sorted == word2Sorted;
}
Я пропустил такие вещи, как нечувствительность к регистру или игнорирование пробелов для краткости.