Как удалить повторяющийся символ в строке в C - PullRequest
1 голос
/ 04 августа 2020

Всего каждого персонажа

Из-за длительного карантина Джоджо очень скучно. Чтобы избавиться от скуки, Джоджо предлагает сыграть с Биби. Игра подсчитывает общее количество каждого символа в слове. Поскольку Джоджо очень хочет выиграть, он просит вас помочь ему угадать результат игры.

Формат ввода

Ввод начинается с целого числа T, количества тестовых примеров . Каждый тестовый пример начинается со строки, содержащей единственную строку W, обозначающую слово. Гарантируется, что слово будет содержать только буквы, цифры c и пробел.

Формат вывода

Каждый тестовый пример будет начинаться со строки "Case #X:", где X представляет тест кейс. После этой строки следует результат каждого символа в слове и общее количество символов. Сначала результат будет отсортирован по алфавиту, а затем будет указан номер.

Ограничения

1 ≤ |?| ≤ 10000

Пример ввода

3
Bina Nusantara University
Binus 2020
Corona Virus Covid 19

Пример вывода

Регистр # 1:

[A] => 4
[B] => 1
[E] => 1
[I] => 3
[N] => 4
[R] => 2
[S] => 2
[T] => 2
[U] => 2
[V] => 1
[Y] => 1

Случай №2:

[B] => 1
[I] => 1
[N] => 1
[S] => 1
[U] => 1
[0] => 2
[2] => 2

Случай №3:

[A] => 1
[C] => 2
[D] => 1
[I] => 2
[N] => 1
[O] => 3
[R] => 2
[S] => 1
[U] => 1
[V] => 2
[1] => 1
[9] => 1

Что я пробовал:

#include<stdio.h>
#include<string.h>

int main(){
    
    int tc, count=0, len;
    char str[500][500];
    
    scanf("%d", &tc); getchar();
    for(int i = 0; i < tc; i++){
        scanf("%[^\n]", str[i]); getchar();
        len = strlen(str[i]);
        printf("Case #%d:\n",i+1);
        for(int j = 0; j < len; j++){
            for(int k = 0; k < len; k++){
                if(str[i][j] >= 97 && str[i][j] <= 122) str[i][j]-=32;
                if(str[i][j] == 32) continue;
                if(str[i][j] == str[i][k]) count++;
                // remove duplicate char
                if(str[i][j] == str[i][k]){
                    
                }
            }
            printf("[%c] => %d\n", str[i][j], count);
            count=0;
        }
        printf("\n");
    }
        
    return 0;
}

1 Ответ

2 голосов
/ 05 августа 2020

Один из наиболее простых c подходов, когда вам нужно подсчитать, сколько раз любой элемент в коллекции встречается для данного набора, - это использовать Frequency Array . Очень просто, Frequency Array содержит количество элементов, которые могут встречаться в коллекции. (например, с какой частотой встречается объект, сопоставленный с каждым индексом?)

Например, если вы хотите знать, сколько раз какой-либо альфа-символ встречается в строке текста (без учета регистра), ваш В коллекции 26 элементов (буквы алфавита). Таким образом, вы просто объявляете массив из 26 элементов (обычно int или size_t), инициализируете все нулями , а затем l oop над символами в вашей строке текста и для каждого альфа-символ, вы увеличиваете соответствующий элемент массива.

Например, с массивом int chars[26] = {0}; и для строки, содержащей "Dog", вы просто увеличиваете:

chars[toupper(line[0]) - 'A']++;   /* increments index chars[3]++  */
chars[toupper(line[1]) - 'A']++;   /* increments index chars[14]++ */
chars[toupper(line[2]) - 'A']++;   /* increments index chars[6]++  */

(см. Таблицу ASCII и описание , чтобы понять, как toupper(line[0]) - 'A' сопоставляет символ с соответствующим индексом. Также обратите внимание, что приведение к unsigned char намеренно опущено для ясности)

После цикла по всем символам в строке вы можете вывести результаты, перебирая все элементы массива частот, и если значение в индексе больше нуля, вы выводите символ, соответствующий этому индексу, и значение, удерживаемое как счетчик, например

for (int i = 0; i < 26; i++)
    if (chars[i])
        printf ("[%c] => %d\n", i + 'A', chars[i]);

Чтобы обработать символы di git в строке, вы просто используете второй 10-элементный частотный массив и делаете то же самое, но на этот раз subt racting '0' для сопоставления цифр ASCII с элементами 0-9 массива.

Другой аспект проблемы, который вы пропустили, - это проверка каждого ввода и преобразования. Вы не можете правильно использовать какую-либо функцию ввода, если не проверит возврат , чтобы определить, успешно ли завершилась операция. То же самое относится к каждому преобразованию в тип numeri c и к любому другому выражению, критически важному для продолжения определенной операции вашего кода.

Собирая части вместе, вы можете использовать глобальный enum для определения необходимых констант. для вашей программы (или к тому же с несколькими операторами #define) и откройте файл, прочтите и преобразуйте первую строку в целочисленное значение с помощью:

#include <stdio.h>
#include <ctype.h>

enum { DIGITS=10, CHARS=26, MAXC=1024 };    /* constants for use in program */

int main (int argc, char **argv) {
    
    char line[MAXC];        /* buffer to hold each line of input */
    int ncases = 0;         /* integer for number of cases */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    if (!fgets (line, MAXC, fp)) {              /* read/validate 1st line */
        fputs ("(user canceled input)\n", stdout);
        return 0;
    }
    if (sscanf (line, "%d", &ncases) != 1) {    /* convert/validate to int */
        fputs ("error: invalid integer input for ncases.\n", stderr);
        return 1;
    }
    

Теперь с количеством случаев в ncases, вы просто l oop это количество раз, считывая следующую строку из файла, перебирая каждый символ в line, увеличивая соответствующие элементы двух частотных массивов chars и digits для подсчета вхождений каждого типа символа (alpha и digits), а затем вывести результаты, последовательно просматривая каждый частотный массив, чтобы вывести счетчики из каждого. Вы можете сделать это следующим образом:

    for (int i = 0; i < ncases; i++) {      /* loop ncases times */
        int chars[CHARS] = {0},             /* frequency array for characters */
            digits[DIGITS] = {0};           /* frequency array for digits */
        
        if (!fgets(line, MAXC, fp)) {       /* read/validate line */
            fputs ("error: reading line from file.\n", stderr);
            return 1;
        }
        
        for (int j = 0; line[j]; j++) {     /* loop over each char in line */
            int c = toupper((unsigned char)line[j]);    /* convert to uppercase */
            if (isalpha((unsigned char)c))          /* check if A-Z */
                chars[c-'A']++;                     /* increment chars at index */
            else if (isdigit((unsigned char)c))     /* check if 0-9 */
                digits[c-'0']++;                    /* increment digits at index */
        }
        
        printf ("\nCase #%d:\n\n", i + 1);          /* output case no. */
        for (int j = 0; j < CHARS; j++)             /* loop over chars array */
            if (chars[j])                           /* if value at index non-zero */
                printf ("[%c] => %d\n", j + 'A', chars[j]); /* output count */
        for (int j = 0; j < DIGITS; j++)            /* loop over digits array */
            if (digits[j])                          /* if value at index non-zero */
                printf ("[%d] => %d\n", j, digits[j]);  /* output count */
    }

( примечание: для вывода количества цифр, нет необходимости сопоставлять индексы с их значением ASCII - вы можете просто вывести целочисленное представление с %d вместо сопоставления j + '0' для вывода символов ASCII с %c - действительно ваш выбор. Также см. man 3 isalpha для требования, чтобы каждый аргумент любой из классификации макросы должны быть типа unsigned char - объясняя цель приведенных выше приведений к (unsigned char))

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

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
    
    return 0;
}

Пример использования / вывода

Размещение образца ввода в файл dat/charcountlines.txt а затем предоставление этого в качестве входных данных для программы приведет к следующему:

$ ./bin/charcount dat/charcountlines.txt

Case #1:

[A] => 4
[B] => 1
[E] => 1
[I] => 3
[N] => 4
[R] => 2
[S] => 2
[T] => 2
[U] => 2
[V] => 1
[Y] => 1

Case #2:

[B] => 1
[I] => 1
[N] => 1
[S] => 1
[U] => 1
[0] => 2
[2] => 2

Case #3:

[A] => 1
[C] => 2
[D] => 1
[I] => 2
[N] => 1
[O] => 3
[R] => 2
[S] => 1
[U] => 1
[V] => 2
[1] => 1
[9] => 1

Приведенное выше соответствует указанному вами выводу и порядку. Просмотрите все и дайте мне знать, если у вас возникнут дополнительные вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...