Сравнивание строк в СИ
Добрый день!
Задача: проверить, состоят ли два слова из одинаковых символов (при этом регистр букв игнорируется, и порядок букв в словах не имеет значения)
Первый способ решения:
- Создавал две копии этих слов
- Затем в этих копиях менял весь регистр на нижний
- Сортировал символы в копиях в алфавитном порядке
- Затем просто запускал цикл, который сравнивал был каждый символ первой копии с каждым символом другой копии. Если буквы не совпали, буквы в словах разные.
Однако мне дали по шапке из-за использовании сортировки.. (Я так и не понял почему)
Второй способ решения:
#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 шт):
Есть ещё такой метод, вполне себе порядка O(n):
- делаете два
intмассива длинной в словарь ваших символов и со значениями0 - идёте по каждой из строк и прибавляете
1в месте массива, соответствующем позиции символа в словаре, т.е. что-то типа в позицииord(ch) - ord('A') - сравниваете эти два массива на равенство
Поскольку словарь английских букв весьма небольшой, места нужно немного. Да и даже если русские буквы будут, всё-равно это немного.
Но можно ещё оптимальнее - делаете один словарь, и идя по одной строке в него добавляете, а потом идя по второй строке вычитаете. Первое же отрицательное значение счётчика - облом, строки разные. Дошли до конца не обломавшись - проверяете, что массив из одних нулей, иначе строки опять же разные.
P.S. В принципе, если сразу сравнить длину строк (если разная - строки уже разные), то дохождение до конца без единого отрицательного счётчика уже будет означать, что строки одинаковые, проверять на нули не нужно будет.