Один из способов определения меры «общего сходства без учета порядка» состоит в использовании некоторого вида расстояния на основе сжатия . По сути, большинство алгоритмов сжатия (например, gzip
) работают для сканирования вдоль строки в поисках сегментов строки, которые появились ранее - каждый раз, когда такой сегмент обнаруживается, он заменяется парой (смещение, длина), идентифицирующей предыдущий сегмент для использования. Вы можете использовать показатели того, насколько хорошо две строки сжимаются, чтобы обнаружить сходство между ними.
Предположим, у вас есть функция string comp(string s)
, которая возвращает сжатую версию s
. Затем вы можете использовать следующее выражение как «показатель сходства» между двумя строками s
и t
:
len(comp(s)) + len(comp(t)) - len(comp(s . t))
, где .
принимается за конкатенацию. Идея состоит в том, что вы измеряете, сколько дальше вы можете сжать t
, посмотрев сначала s
. Если s == t
, то len(comp(s . t))
будет чуть больше len(comp(s))
, и вы получите высокий балл, а если они совершенно другие, len(comp(s . t))
будет очень близко к len(comp(s) + comp(t))
, и вы получите оценка около нуля. Промежуточные уровни сходства дают промежуточные баллы.
На самом деле следующая формула еще лучше, поскольку она симметрична (то есть оценка не меняется в зависимости от того, какая строка s
, а какая t
):
2 * (len(comp(s)) + len(comp(t))) - len(comp(s . t)) - len(comp(t . s))
Эта техника имеет свои корни в теории информации.
Преимущества: хорошие алгоритмы сжатия уже доступны, поэтому вам не нужно много писать, и они работают за линейное время (или почти), поэтому они быстрые. Напротив, решения, включающие все перестановки слов, растут сверх экспоненциально по количеству слов (хотя, по общему признанию, это не может быть проблемой в вашем случае, поскольку вы говорите, что знаете, что будет только несколько слов).