Алгоритм анаграммы с минимальной сложностью
недавно меня попросили разработать алгоритм, который проверяет, являются ли две строки анаграммами друг друга. Моей целью было минимизировать пространственно-временную сложность, поэтому я придумал такой алгоритм:
- создать массив из 26 элементов, каждый из которых инициализируется нулями.
- пересеките первую строку и для каждого символа увеличьте элемент массива, соответствующий этому символу.
- пересеките вторую строку и для каждого символа уменьшите массив элемент, соответствующий этому символу.
- сканировать массив. Если все элементы равны 0, две строки являются анаграммами.
однако временная сложность этого алгоритма равна O (n), и я не могу придумать алгоритм с меньшей сложностью. Кто-нибудь знает об этом?
5 ответов
ваш алгоритм асимптотически оптимален. Решить эту проблему лучше, чем за Ω(n) раз, невозможно. Чтобы увидеть это, предположим, что существует алгоритм A, который может решить проблему за o (n) время (обратите внимание, что здесь мало-o из n). Тогда для любого 1 > ε > 0 существует N таких, что для любого ввода размера не менее n алгоритм должен заканчиваться не более чем на en шагов. Установите ε = 1/3 и рассмотрите любые входы в алгоритм, которые имеют длину не менее n для вышеупомянутого n для этого ε. Поскольку алгоритм может смотреть не более 1/3 символов в двух строках, то должны быть два разных входа в функцию, один из которых является парой анаграмм, а другой-нет, так что алгоритм смотрит на одно и то же подмножество символов каждого входа. В этом случае функция должна будет выдавать один и тот же результат в каждом случае и, таким образом, будет ошибочной по крайней мере на одном из входов. Мы пришли к противоречию, поэтому такой алгоритм не должен существовать.
вы могли бы улучшить среднюю производительность с ранними выходами. При сканировании 2-й строки, если count[char] равен 0 перед уменьшением, у вас нет анаграммы, и вы можете остановить сканирование.
кроме того, если строки короче 26 символов, то на последнем шаге проверьте только символы в первой строке на нули.
Это не меняет большого O, но может изменить ваше среднее время выполнения на что - то меньшее, чем 2n+26 o предлагаемое решение, в зависимости от ваших данных.
чтобы убедиться, что строки являются анаграммами, вам нужно сравнить все строки - так как это может быть быстрее, чем o(n)?
давайте вопрос: Учитывая две строки s и t, напишите функцию, чтобы определить, является ли t анаграммой s.
например, s = "anagram", t = "nagaram", возвращает true. s = "крыса", t = "автомобиль", возврат false.
Метод 1 (С Помощью HashMap):
public class Method1 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
Map<Character ,Integer> map = new HashMap<>();
for( char c : a.toCharArray()) {
map.put(c, map.getOrDefault(c, 0 ) + 1 );
}
for(char c : b.toCharArray()) {
int count = map.getOrDefault(c, 0);
if(count == 0 ) {return false ; }
else {map.put(c, count - 1 ) ; }
}
return true;
}
}
Способ 2 :
public class Method2 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b));// output=> true
}
private static boolean isAnagram(String a, String b) {
int[] alphabet = new int[26];
for(int i = 0 ; i < a.length() ;i++) {
alphabet[a.charAt(i) - 'a']++ ;
}
for (int i = 0; i < b.length(); i++) {
alphabet[b.charAt(i) - 'a']-- ;
}
for( int w : alphabet ) {
if(w != 0 ) {return false;}
}
return true;
}
}
Способ 3 :
public class Method3 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
char[] ca = a.toCharArray() ;
char[] cb = b.toCharArray();
Arrays.sort( ca );
Arrays.sort( cb );
return Arrays.equals(ca , cb );
}
}
Способ 4 :
public class Method4 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
//String c = "gini";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
Map<Integer, Integer> map = new HashMap<>();
a.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) + 1));
b.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) - 1));
//System.out.println(map.values());
for(int count : map.values()) {
if (count<0) return false;
}
return true;
}
}
int anagram (char a[], char b[]) {
char chars[26];
int ana = 0;
int i =0;
for (i=0; i<26;i++)
chars[i] = 0;
if (strlen(a) != strlen(b))
return -1;
i = 0;
while ((a[i] != '') || (b[i] != '')) {
chars[a[i] - 'a']++;
chars[b[i] - 'a']--;
i++;
}
for (i=0; i<26;i++)
ana += chars[i];
return ana;
}
void main() {
char *a = "chimmy";
char *b = "yimmch";
printf ("Anagram result is %d.\n", anagram(a,b));
}