Один из вариантов состоит в том, чтобы подсчитывать числа каждого символа в каждой строке и сравнивать подсчеты. Простая реализация должна принимать O(max(N, A))
время, где N - длина большей строки, а A - размер массива, который вы используете для хранения счетчиков. Например, в Java:
public boolean equalIgnoringOrder(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}
// Assuming characters in the range ASCII 0 to 127
int[] c1 = new int[128];
int[] c2 = new int[128];
for (int i = 0; i < s1.length(); i++) {
c1[s1.charAt(i)]++;
c2[s2.charAt(i)]++;
}
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
return false;
}
}
return true;
}
Возможны некоторые улучшения. Например, вы можете справиться с произвольным набором символов, выполнив уменьшение диапазона; то есть выполнить начальный проход через s1
и s2
, ища наименьшие и наибольшие символы в каждом из них, и использовать его для определения размера c1
и c2
и базового смещения. Это будет использовать меньше места в среднем и сократить время для инициализации массивов count. Он также предлагает короткое замыкание для сравнения; например когда самые маленькие и самые большие символы для s1
и s2
не совпадают.
Для сравнения, сравнение строк, отсортированных с использованием heapsort или quicksort, будет O(NlogN)
в среднем с пространством O(N)
, где N - длина большей длины.
Однако, как указывает @pst, константы пропорциональности могут сделать алгоритм O(NlogN)
или даже O(N*N)
лучше алгоритма O(N)
, если N не велико. В этом случае средние длины сравниваемых строк, вероятно, являются наиболее важным фактором.
Приведенный выше код эффективно выполняет сортировку Radix с несколькими короткими замыканиями. (Три, если вы включаете короткое замыкание, связанное с уменьшением диапазона.) Таким образом, в конечном счете это сводится к тому, будет ли лучше сортировка быстрой сортировки/кучи или сортировка по радиусу. И это зависит от длины входных строк и диапазонов символов.
На другом уровне. @ В ответе Джона предлагается вычислить произведение простых чисел. Если мы сделаем вычисление с использованием произвольного представления точности, результирующие значения будут уникальными для каждого отдельного набора строк «равного игнорирования порядка». К сожалению, вычисление будет O(N*N)
. (Каждый промежуточный продукт имеет O(N)
цифр, а умножение N-значного числа на константу - O(N)
. Сделайте это для N символов, и вы получите O(N*N)
.)
Но если мы сделаем вычисление по модулю (скажем) 64, результат будет действительно хорошим хешем, который нечувствителен к порядку символов; например
long hash = 1;
for (int i = 0; i < s.length(); i++) {
hash = hash * primes[s.charAt(i)];
}
Итак, я хотел бы утверждать, что алгоритм, который дает лучшую производительность и пространство использование в среднем для сравнения случайно генерируемых строк, вероятно, будет в форме:
if (s1.length() != s2.length()) {
return false;
}
if (hash(s1) != hash(s2)) { // computed as above
return false;
}
// Compare using sorting or character counting as above.
One конечная точка. Если предположить, что указатели строк не идентичны и что строки имеют неравную длину, любой алгоритм, который вычисляет предикат equals
, должен быть по адресу O(N)
или хуже. Он должен исследовать каждый символ в обеих строках, чтобы сделать это определение, и он принимает O(N)
операций.
Любой алгоритм, который делает менее 2 * N
получений фидов или уточняющие менее 2 * N
операции на принесенных значений в этом сценарии доказуемо неверна.
Вам нравятся персонажи дураков? Являются ли «abcd» и «abcdcba» равными? – popester
Можете ли вы обосновать свою потребность в «эффективности»? Большинство людей бросают Кнут на вас, если вы не можете. :) –
проясните на «арендных» матчах «тернакт» - это что-то такое, что «тернакт» также соответствует «аренде» или нет? Дополнительные примеры помогут ... – Alnitak