Search code examples
calgorithmtrie

Incorrect code to check if a word can be made of smaller given words (word break)


Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?

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

/* Node structure */
typedef struct node {
    int letter[26];
    struct node* next[26];
    int is_word;
} node;


/* Create node   */
node* getnode(void) {
    node* p = malloc(sizeof(node));
    int i;
    for (i = 0; i < 1004; i++) {
        p->letter[i] = 0;
        p->next[i] = NULL;
    }
    p->is_word = 0;

    return p;
}

/* make dictionary  */
void fill_dictionary(char word[], node* start) {
    int len = strlen(word), i;
    node* temp = start;

    for (i = 0; i < len; i++) {
        if (temp->letter[word[i] % 'a'] == 0) {
            temp->letter[word[i] % 'a'] = 1;
            temp->next[word[i] % 'a'] = getnode();
            temp = temp->next[word[i] % 'a'];
        } else {
            temp = temp->next[word[i] % 'a'];
        }
    }

    temp->is_word = 1;
    return;
}

int spell_check(char line[100003], node* start) {
    int len = strlen(line), i, flag = 0;
    node* temp = start;

    for (i = 0; i < len; i++) {
        if (temp->letter[line[i] % 'a'] == 0) {
            return 1;
        } else {
            temp = temp->next[line[i] % 'a'];
            flag = 0;

            if (temp->is_word == 1) {
                flag = 1;
                temp = start;
            }
        }
    }

    if (flag == 1) {
        return 0;
    } else {
        return 1;
    }
}

int main(void) {
    int n, i, ans, m;
    scanf("%d %d", &n,&m);  // no. of words in dictionary
    node* start = getnode();

    for (i = 0; i < n; i++) {
        char word[11];      // max length of dictionary word
        scanf("%s", word);
        fill_dictionary(word, start);
    }

    scanf("%d", &n);        // no. of lines to be checked

    for (i = 0; i < n; i++) {
        char line[100003];  // max length of a line
        scanf("%s", line);
        ans = spell_check(line, start);

        if (ans == 0) {
            printf("YES\n");
        } else {
            printf("NO\n");
        }
    }

    return 0;
}

Solution

  • Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.

    Good luck!

    Example:

    $ gcc -o wordsplitter wordsplitter.c

    $ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse

    xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define DICTIONARY_FILEPATH  "dictionary.txt"
    #define MAX_WORD_SIZE  100
    /*
     * Error codes (usually this is put in a header file and included)
     */
    #define SUCCESS         0
    #define FILE_NOT_FOUND -1
    #define OUT_OF_MEMORY  -2
    
    typedef struct word {
        struct word *next;
        char *word;
    } word_t;
    
    word_t *dictionaryListhead = NULL;
    
    typedef struct wordsubcomponent {
        struct wordsubcomponent *next;
        char *text;
        int isDictionaryWord;
    } wordsubcomponent_t;
    
    int
    loadDictionaryFromFile(char *filename, word_t **listhead)
    {
        char wordFromFile[MAX_WORD_SIZE];
        word_t *lastWordStored = NULL;
    
        FILE *dictionaryFile = fopen(filename, "r"); 
        if (dictionaryFile == NULL) {
            return FILE_NOT_FOUND;
        }    
        while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
            word_t *newDictionaryWordNode;
            if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
                return OUT_OF_MEMORY;
            }
            char *cp = strchr(wordFromFile, '\n');
            if (cp != NULL)
                *cp = '\0'; // get rid of trailing \n
    
            newDictionaryWordNode->word = strdup(wordFromFile);     
            if (*listhead == NULL) {
                lastWordStored = *listhead = newDictionaryWordNode;
            } else {
                lastWordStored = lastWordStored->next = newDictionaryWordNode;
            }
        }
        fclose(dictionaryFile);
        return SUCCESS;
    }
    
    wordsubcomponent_t 
    *newsubcomponent() {
        wordsubcomponent_t *subcomp = NULL;
        if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) { 
            subcomp->text = strdup("");  // seed with empty string (instead of NULL) so we can append
        } else {
            fprintf(stderr, "out of memory (fatal). program exiting\n");
            exit(-1);
        }
        return subcomp;
    }
    
    /*
     * Returns an linked list of word subcomponents for the given word, split up around dictionary words
     */
    wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
        wordsubcomponent_t *subcomponents, *currSubcomp;
        subcomponents = currSubcomp = newsubcomponent();
        for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
            int matchFlag = 0;
            for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
                if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
                    if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
                        currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
                    currSubcomp->text = wordNode->word; // save dict-word in subcomp
                    currSubcomp->isDictionaryWord = 1;
                    currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
                    cp += strlen(wordNode->word); // advance cp past extracted dict-word
                    matchFlag = 1;
                    break; // break out of inner-loop
                }
            }
            if (!matchFlag)  { // No dict-word found at cp      
                char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.         
                strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
            }
        }
        return subcomponents;
    }
    
    void
    dumpDictionary(word_t *listhead) {
        printf("\nList of dictionary words:\n");
        printf("----------------\n");
        for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
            printf("   %s\n", wordNode->word);
        }
        printf("----------------\n\n");
    }
    
    int 
    main(int argc, char **argv) 
    {
        int status;
        if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
            switch(status) {
            case FILE_NOT_FOUND:
                fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
                break;
            case OUT_OF_MEMORY:
                fprintf(stderr, "Out of memory");
                break;
            }
            return EXIT_FAILURE;
        }
    
        /*
         * Load dictionary first so we can show them the list of words if they didn't
         * pass in a command line argument with the word to parse.
         */    
        if (argc < 2) {
            fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
            dumpDictionary(dictionaryListhead);
            return EXIT_FAILURE;
        }
    
        wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
        while(subcomp != NULL && strlen(subcomp->text) > 0) {
            if (subcomp->isDictionaryWord) 
                printf("\"%s\" ", subcomp->text);
            else
                printf("%s ", subcomp->text);
            subcomp = subcomp->next;
        }
        printf("\n");
        return EXIT_SUCCESS;
    }