В общем, вот медленный вариант, но вроде работающий.
Первым делом, код расстояние между двумя словами (просто Левенштейн)
public int MinDistance(string word1, string word2)
{
var map = new int[word1.Length + 1, word2.Length + 1];
for (var i = 1; i <= word1.Length; i++) map[i, 0] = i;
for (var i = 1; i <= word2.Length; i++) map[0, i] = i;
for (var i = 1; i <= word1.Length; i++)
{
for (var j = 1; j <= word2.Length; j++)
{
var side = Math.Min(map[i - 1, j] + 1, map[i, j - 1] + 1);
map[i, j] = Math.Min(map[i - 1, j - 1] + (word1[i - 1] == word2[j - 1] ? 0 : 1), side);
}
}
return map[word1.Length, word2.Length];
}
Зная левенштейн, можно для строк, состоящих из слов, составить матрицу сопоставления слов. Я делаю матрицу квадратной специально, чтобы потом проще было считать, ведь для расстояния между наборами слов все слова должны участвовать
public int DiffLine(string w1, string w2)
{
var words1 = w1.Split();
var words2 = w2.Split();
var size = Math.Max(words1.Length, words2.Length);
var map = new int[size, size];
for(int i=0; i<size; i++)
for (int j = 0; j < size; j++)
{
var word1 = i >= words1.Length ? string.Empty : words1[i];
var word2 = j >= words2.Length ? string.Empty : words2[j];
map[i, j] = MinDistance(word1, word2);
}
return MinDistance(words1, words2, map, new HashSet<int>());
}
Имея мапу, я делаю тупо перебор вариантов - тут можно вроде как улучшить, у меня просто пока идей нет как =)
public int MinDistance(string[] words1, string[] words2, int[,] distances, HashSet<int> rowsTaken)
{
if (rowsTaken.Count == distances.GetLength(0)) return 0;
int ret = int.MaxValue;
for(int i=0; i<distances.GetLength(0); i++)
{
if (rowsTaken.Contains(i)) continue;
rowsTaken.Add(i);
for(int j=0; j<distances.GetLength(1); j++)
{
int dist = distances[i, j] + MinDistance(words1, words2, distances, rowsTaken);
ret = Math.Min(ret, dist);
}
rowsTaken.Remove(i);
}
return ret;
}
Ну и в итоге, можно сравнивать строки с учетом слов, пример кода
var wordsLeft = new[] {"вкусный пряник", "радужный"};
var wordsRight = new[] {"пряник вкусный"};
for(int i=0; i<wordsLeft.Length; i++){
for(int j=0; j<wordsRight.Length; j++)
{
Console.WriteLine($"{wordsLeft[i]} <-> {wordsRight[j]} : {DiffLine(wordsLeft[i], wordsRight[j])}");
}
}
Выдаст результат
вкусный пряник <-> пряник вкусный : 0
радужный <-> пряник вкусный : 10
Код писал на сишарпе, но на джаву он легко переносится.