Алгоритм анаграммы с минимальной сложностью

недавно меня попросили разработать алгоритм, который проверяет, являются ли две строки анаграммами друг друга. Моей целью было минимизировать пространственно-временную сложность, поэтому я придумал такой алгоритм:

  1. создать массив из 26 элементов, каждый из которых инициализируется нулями.
  2. пересеките первую строку и для каждого символа увеличьте элемент массива, соответствующий этому символу.
  3. пересеките вторую строку и для каждого символа уменьшите массив элемент, соответствующий этому символу.
  4. сканировать массив. Если все элементы равны 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));


}