Сравнивание строк в СИ

Добрый день!

Задача: проверить, состоят ли два слова из одинаковых символов (при этом регистр букв игнорируется, и порядок букв в словах не имеет значения)

Первый способ решения:

  • Создавал две копии этих слов
  • Затем в этих копиях менял весь регистр на нижний
  • Сортировал символы в копиях в алфавитном порядке
  • Затем просто запускал цикл, который сравнивал был каждый символ первой копии с каждым символом другой копии. Если буквы не совпали, буквы в словах разные.

Однако мне дали по шапке из-за использовании сортировки.. (Я так и не понял почему)

Второй способ решения:

#include <stdio.h>
#include <stdlib.h>

int word_size(char* s) {
    int c = 0;
    while (s[c] != '\0') {
        ++c;
    }
    return c;
}

void copy(char to[], char from[], int size) {
    int i = 0;
    while (i < size) {
        to[i] = from[i];
        ++i;
    }
}

int compare(char* s, char* t, int size) {
    char* copy_2 = (char*) malloc(size);
    copy(copy_2, t, size);
    int total_replacements = 0;
        
    for (int i = 0; i < size; ++i) {
        char el_to_find = s[i];
        for (int j = 0; j < size; ++j) {
            if (copy_2[j] == el_to_find) {
                copy_2[j] = '*';
                ++total_replacements;
                break;
            }
        }
    }
        
    if (total_replacements == word_size(s)) {
        free(copy_2);
        return 0;
    } else {
        free(copy_2);
        return 1;
    }
}

int main() {
    char* s = "HELLO";
    char* t = "HELLO";
    //Let the both sizes be equal
    //Перед сравнением надо поменять регистр, но это потом
    printf("%d\n", compare(s, t, word_size(s)));
    return 0;
}

Во втором способе я отказался от сортировке и таким образом вот мой второй алгоритм:

  • Создавал одну копию одного из двух слов
  • Далее при помощи двух циклов искал каждый i-й элемент из первой строки по всей второй строке
  • Если такой нашелся, то во второй строке этот символ заменяем на '*' (я решил заменять буквы, так как они могут повторяться)
  • И после этих циклов проверяю кол-во замен. Если кол-во замен равняется длине строк, то значит все буквы совпали, следовательно, слова состоят из одинаковых букв.

Второй способ мне не кажется таким уж оптимальным. Поэтому я хочу задать вопрос по третьему способу.

Третий способ:

#include <stdio.h>

int word_size(char* s) {
    int c = 0;
    while (s[c] != '\0') {
        ++c;
    }
    return c;
}

int compare(char* s, char* t, int size) {
  int sum_s = 0, sum_t = 0;
  for (int i = 0; i < size; ++i) {
    sum_s += s[i];
    sum_t += t[i];
  }
  if (sum_s == sum_t) {

    return 0;
  } else {
    return 1;
  }
}

int main() {
  char* s = "ABCD";
  char* t = "CDE1";
  //Let the size of the strings be equal
  //Предже чем сравнивать, необходимо поменять регистр, но это потом
  printf("%d\n", compare(s, t, word_size(s)));
  return 0;
}

В третьем способе я просто нахожу сумму символов каждого слова и затем эти две суммы сравниваю. Но ведь это точно не может значить, что буквы в словах совпадают, верно? Мне нужна помощь, как мне полностью доделать третий способ, чтобы он точно определял, совпадают ли буквы в словах.

Или быть может у кого-то есть алгоритм получше?

Заранее благодарен!!


Ответы (1 шт):

Автор решения: CrazyElf

Есть ещё такой метод, вполне себе порядка O(n):

  • делаете два int массива длинной в словарь ваших символов и со значениями 0
  • идёте по каждой из строк и прибавляете 1 в месте массива, соответствующем позиции символа в словаре, т.е. что-то типа в позиции ord(ch) - ord('A')
  • сравниваете эти два массива на равенство

Поскольку словарь английских букв весьма небольшой, места нужно немного. Да и даже если русские буквы будут, всё-равно это немного.

Но можно ещё оптимальнее - делаете один словарь, и идя по одной строке в него добавляете, а потом идя по второй строке вычитаете. Первое же отрицательное значение счётчика - облом, строки разные. Дошли до конца не обломавшись - проверяете, что массив из одних нулей, иначе строки опять же разные.

P.S. В принципе, если сразу сравнить длину строк (если разная - строки уже разные), то дохождение до конца без единого отрицательного счётчика уже будет означать, что строки одинаковые, проверять на нули не нужно будет.

→ Ссылка