diff --git a/030_substring_with_concatenation_of_all_words/concatenation.c b/030_substring_with_concatenation_of_all_words/concatenation.c index 8d93d94..ababaa9 100644 --- a/030_substring_with_concatenation_of_all_words/concatenation.c +++ b/030_substring_with_concatenation_of_all_words/concatenation.c @@ -20,16 +20,27 @@ static inline int BKDRHash(char *s, size_t size) static int find(char *word, struct word_hash *table, int size) { - int i, first = 1, hash = BKDRHash(word, size); - for (i = hash; first || i != hash; i = ++i % size) { - first = 0; + int hash = BKDRHash(word, size); + int i = hash; + do { if (table[i].freq > 0 && !strcmp(table[i].word, word)) { return i; } - } + i = ++i % size; + } while (i != hash); return -1; } +static void add(char *word, struct word_hash *table, int size) +{ + int i, hash = BKDRHash(word, size); + for (i = hash; table[i].freq > 0 && strcmp(table[i].word, word); i = ++i % size) {} + if (table[i].freq == 0) { + table[i].word = word; + } + table[i].freq++; +} + /** ** Return an array of size *returnSize. ** Note: The returned array must be malloced, assume caller calls free(). @@ -44,7 +55,7 @@ static int *findSubstring(char *s, char **words, int wordsSize, int *returnSize) int i, j, cap = 500, count = 0; char *start = s; struct word_node *wn; - int hash_size = wordsSize; + int hash_size = wordsSize * 2; int len = strlen(words[0]); char *word = malloc(len + 1); int *indexes = malloc(cap * sizeof(int)); @@ -53,12 +64,7 @@ static int *findSubstring(char *s, char **words, int wordsSize, int *returnSize) memset(table, 0, hash_size * sizeof(*table)); for (i = 0; i < wordsSize; i++) { - int hash = BKDRHash(words[i], hash_size); - for (j = hash; table[j].freq > 0 && strcmp(table[j].word, words[i]); j = ++j % hash_size) {} - if (table[j].freq == 0) { - table[j].word = words[i]; - } - table[j].freq++; + add(words[i], table, hash_size); } word[len] = '\0'; diff --git a/127_word_ladder/Makefile b/127_word_ladder/Makefile new file mode 100644 index 0000000..eb51704 --- /dev/null +++ b/127_word_ladder/Makefile @@ -0,0 +1,2 @@ +all: + gcc -O2 -o test word_ladder.c diff --git a/127_word_ladder/word_ladder.c b/127_word_ladder/word_ladder.c new file mode 100644 index 0000000..3059ae9 --- /dev/null +++ b/127_word_ladder/word_ladder.c @@ -0,0 +1,199 @@ +#include +#include +#include + +struct hlist_node; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +static inline void INIT_HLIST_HEAD(struct hlist_head *h) { + h->first = NULL; +} + +static inline void INIT_HLIST_NODE(struct hlist_node *n) { + n->next = NULL; + n->pprev = NULL; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + if (h->first != NULL) { + h->first->pprev = &n->next; + } + n->next = h->first; + n->pprev = &h->first; + h->first = n; +} + +struct list_head { + struct list_head *next, *prev; +}; + +static inline void +INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list->prev = list; +} + +static inline int +list_empty(const struct list_head *head) +{ + return (head->next == head); +} + +static inline void +__list_add(struct list_head *new, struct list_head *prev, struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void +list_add(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head, head->next); +} + +static inline void +list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +static inline void +__list_del(struct list_head *entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +static inline void +list_del(struct list_head *entry) +{ + __list_del(entry); + entry->next = entry->prev = NULL; +} + +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (size_t)&(((type *)0)->member))) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, field) list_entry((ptr)->next, type, field) +#define list_last_entry(ptr, type, field) list_entry((ptr)->prev, type, field) + +#define list_for_each(p, head) \ + for (p = (head)->next; p != (head); p = p->next) + +#define list_for_each_safe(p, n, head) \ + for (p = (head)->next, n = p->next; p != (head); p = n, n = p->next) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; true; }); pos = n) + +struct word_node { + int step; + char *word; + struct hlist_node node; + struct list_head link; +}; + +static int BKDRHash(char* str, int size) +{ + int seed = 131; // 31 131 1313 13131 131313 etc.. + unsigned int hash = 0 ; + while (*str != '\0') { + hash = hash * seed + (*str++); + } + return hash % size; +} + +static struct word_node *find(char *word, struct hlist_head *hhead, int size) +{ + struct hlist_node *p; + int hash = BKDRHash(word, size); + hlist_for_each(p, &hhead[hash]) { + struct word_node *node = list_entry(p, struct word_node, node); + if (node->step == 0 && !strcmp(node->word, word)) { + return node; + } + } + return NULL; +} + +static int ladderLength(char* beginWord, char* endWord, char** wordList, int wordListSize) +{ + int i, len = strlen(beginWord); + char *word = malloc(len + 1); + struct list_head queue; + struct word_node *node; + + struct hlist_head *hhead = malloc(wordListSize * sizeof(*hhead)); + for (i = 0; i < wordListSize; i++) { + INIT_HLIST_HEAD(hhead + i); + } + + /* Add into hash list */ + for (i = 0; i < wordListSize; i++) { + node = malloc(sizeof(*node)); + node->word = wordList[i]; + node->step = 0; + int hash = BKDRHash(wordList[i], wordListSize); + hlist_add_head(&node->node, &hhead[hash]); + } + + INIT_LIST_HEAD(&queue); + struct word_node *first = malloc(sizeof(*node)); + first->word = beginWord; + first->step = 1; + + while (strcmp(first->word, endWord)) { + strcpy(word, first->word); + for (i = 0; i < len; i++) { + char c; + char o = word[i]; + for (c = 'a'; c <= 'z'; c++) { + if (c == o) continue; + word[i] = c; + node = find(word, hhead, wordListSize); + if (node != NULL) { + list_add_tail(&node->link, &queue); + node->step = first->step + 1; + } + } + word[i] = o; + } + + if (list_empty(&queue)) { + return 0; + } else { + first = list_first_entry(&queue, struct word_node, link); + list_del(&first->link); + } + } + + return first->step; +} + +int main(int argc, char **argv) +{ + if (argc < 3) { + fprintf(stderr, "Usage: ./test begin end dict...\n"); + exit(-1); + } + + printf("%d\n", ladderLength(argv[1], argv[2], argv + 3, argc - 3)); + return 0; +}