diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2021-01-10 07:21:57 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-10 07:21:57 +0000 |
| commit | e41b1f3defd60cb045a1fccbbb4d108b0aedc581 (patch) | |
| tree | bac11060f98c5a51a29c25abcbf473e33d798d6f | |
| parent | f53d8f703279156f2655a33fca007fbac19a8cd9 (diff) | |
| parent | 7e468b1ececa0c32861a00a2e8bd1008cc2a9d00 (diff) | |
| download | perlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.tar.gz perlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.tar.bz2 perlweeklychallenge-club-e41b1f3defd60cb045a1fccbbb4d108b0aedc581.zip | |
Merge pull request #3190 from pauloscustodio/094
Add Perl, C, C++, Basic and Forth solutions to challenge 094
| -rw-r--r-- | challenge-094/paulo-custodio/basic/ch-1.bas | 181 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/basic/ch-2.bas | 121 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/c/ch-1.c | 168 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/c/ch-2.c | 200 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/cpp/ch-1.cpp | 71 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/cpp/ch-2.cpp | 156 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/forth/ch-1.fs | 257 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/forth/ch-2.fs | 178 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/perl/ch-1.pl | 51 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/perl/ch-2.pl | 93 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/python/ch-1.py | 48 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/python/ch-2.py | 96 | ||||
| -rw-r--r-- | challenge-094/paulo-custodio/test.pl | 92 |
13 files changed, 1712 insertions, 0 deletions
diff --git a/challenge-094/paulo-custodio/basic/ch-1.bas b/challenge-094/paulo-custodio/basic/ch-1.bas new file mode 100644 index 0000000000..1b85e066dd --- /dev/null +++ b/challenge-094/paulo-custodio/basic/ch-1.bas @@ -0,0 +1,181 @@ +' Challenge 094 +' +' TASK #1 › Group Anagrams +' Submitted by: Mohammad S Anwar +' You are given an array of strings @S. +' +' Write a script to group Anagrams together in any random order. +' +' An Anagram is a word or phrase formed by rearranging the letters of a +' different word or phrase, typically using all the original letters exactly +' once. +' +' Example 1: +' Input: ("opt", "bat", "saw", "tab", "pot", "top", "was") +' Output: [ ("bat", "tab"), +' ("saw", "was"), +' ("top", "pot", "opt") ] +' Example 2: +' Input: ("x") +' Output: [ ("x") ] + +' List of strings +Type ListNodeType + value as String + nxt as ListNodeType Ptr +End Type + +Type ListType + head as ListNodeType Ptr + tail as ListNodeType Ptr +End Type + + +' Map of keys to lists of strings +Type MapNodeType + key as String + values as ListType + nxt as MapNodeType Ptr +End Type + +Type MapType + head as MapNodeType Ptr + tail as MapNodeType Ptr +End Type + + +Sub list_push(Byref list as ListType, value as String) + Dim node as ListNodeType Ptr + node = Callocate(1, Sizeof(ListNodeType)) + node->value = value + if list.head = 0 Then + list.head = node + list.tail = node + Else + list.tail->nxt = node + list.tail = node + End If +End Sub + +Sub list_delete(Byref list as ListType) + Dim node as ListNodeType Ptr, nxt as ListNodeType Ptr + node = list.head + Do While node <> 0 + nxt = node->nxt + Deallocate(node) + node = nxt + Loop +End Sub + +Sub list_print(Byref list as ListType) + Dim node as ListNodeType Ptr + Print "("; + node = list.head + Do While node <> 0 + If node <> list.head Then Print ", "; + Print """"; node->value; """"; + node = node->nxt + Loop + Print ")"; +End Sub + + +' add/find a key +Function map_add_key(Byref map as MapType, key as String) as ListType Ptr + Dim node as MapNodeType Ptr + If map.head = 0 Then ' map empty + node = Callocate(1, Sizeof(MapNodeType)) + map.head = node + map.tail = node + node->key = key + map_add_key = @node->values + Else + node = map.head + Do While node <> 0 + If node->key = key Then ' found key + map_add_key = @node->values + Exit Function + End If + node = node->nxt + Loop + + ' not found + node = Callocate(1, Sizeof(MapNodeType)) + node->key = key + map.tail->nxt = node + map.tail = node + map_add_key = @node->values + End If +End Function + +' add key/value +Sub map_add_key_value(Byref map as MapType, key as String, value as String) + Dim list as ListType Ptr + list = map_add_key(map, key) + list_push(*list, value) +End Sub + +Sub map_print(Byref map as MapType) + Dim node as MapNodeType Ptr + print "[ "; + node = map.head + Do While node <> 0 + If node <> map.head Then Print ",":Print " "; + list_print(node->values) + node = node->nxt + Loop + Print " ]" +End Sub + +Sub map_delete(Byref map as MapType) + Dim node as MapNodeType Ptr, nxt as MapNodeType Ptr + node = map.head + Do While node <> 0 + nxt = node->nxt + list_delete(node->values) + Deallocate(node) + node = nxt + Loop +End Sub + + +' sort a string - selection sort +Function sort_string(Byval s as String) as String + dim i as Integer, j as Integer, min_i as Integer + dim c as String + + for i=0 to len(s)-1 + min_i=i + for j=i+1 to len(s) + if Asc(Mid(s,j,1)) < Asc(Mid(s,min_i,1)) Then + min_i=j + End If + Next j + + ' swap + c=Mid(s,i,1) + Mid(s,i,1)=Mid(s,min_i,1) + Mid(s,min_i,1)=c + next i + sort_string = s +End Function + + +' read strings from command line, build map +Sub read_strings(Byref map as MapType) + Dim key as String, value as String + Dim i as Integer + i = 1 + Do While Command(i) <> "" + value = Command(i) + key = sort_string(value) + map_add_key_value(map, key, value) + i = i+1 + Loop +End Sub + +' main +Dim map as MapType +read_strings(map) +map_print(map) +map_delete(map) diff --git a/challenge-094/paulo-custodio/basic/ch-2.bas b/challenge-094/paulo-custodio/basic/ch-2.bas new file mode 100644 index 0000000000..13d315b244 --- /dev/null +++ b/challenge-094/paulo-custodio/basic/ch-2.bas @@ -0,0 +1,121 @@ +' Challenge 094 +' +' TASK #2 › Binary Tree to Linked List +' Submitted by: Mohammad S Anwar +' You are given a binary tree. +' +' Write a script to represent the given binary tree as an object and flatten +' it to a linked list object. Finally print the linked list object. +' +' Example: +' Input: +' +' 1 +' / \ +' 2 3 +' / \ +' 4 5 +' / \ +' 6 7 +' +' Output: +' +' 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3 + +' input lines +Dim Shared lines() as String + +' tree node +Type NodeType + value as Integer + left_node as NodeType Ptr + right_node as NodeType Ptr +End Type + + +' read lines from stdin +Sub read_lines() + Dim i as Integer + Open Cons for Input as #1 + i = 0 + Do Until Eof(1) + Redim Preserve lines(i) as String + Line Input #1, lines(i) + i = i+1 + Loop + Close #1 +End Sub + + +' parse lines, produce a tree +Function parse_subtree(row as Integer, col as Integer) as NodeType Ptr + Dim node as NodeType Ptr + + 'parse root + node = Callocate(1, Sizeof(NodeType)) + If node=0 Then End -1 + node->value = Val(Mid(lines(row), col, 1)) + + 'parse children + if row+2 <= UBound(lines) Then + If col-2 >= 1 And Mid(lines(row+1), col-1, 1) = "/" Then + node->left_node = parse_subtree(row+2, col-2) + End If + If col+2 <= Len(lines(row+2)) And Mid(lines(row+1), col+1, 1) = "\" Then + node->right_node = parse_subtree(row+2, col+2) + End If + End If + parse_subtree = node +End Function + +Function parse_tree() as NodeType Ptr + Dim root as String, col as Integer + root = Trim(lines(0)) ' remove spaces, leave only root number + col = InStr(lines(0), root) ' find its column + parse_tree = parse_subtree(0, col) +End Function + +Sub delete_tree(node as NodeType Ptr) + if node->left_node Then delete_tree(node->left_node) + if node->right_node Then delete_tree(node->right_node) + Deallocate(node) +End Sub + + +' flatten a tree +Sub flatten_tree(root as NodeType Ptr) + Dim left_node as NodeType Ptr, right_node as NodeType Ptr, node as NodeType Ptr + If root <> 0 Then + left_node = root->left_node: flatten_tree(left_node) + right_node = root->right_node: flatten_tree(right_node) + + root->left_node = 0 + root->right_node = left_node + + node = root + Do While node->right_node <> 0 + node = node->right_node + Loop + + node->right_node = right_node + End If +End Sub + +Sub print_tree(root as NodeType Ptr) + Dim node as NodeType Ptr + node = root + Do While node <> 0 + If node <> root Then Print " -> "; + Print Trim(Str(node->value)); + node = node->right_node + Loop + Print +End Sub + +' main +Dim tree as NodeType Ptr +read_lines +tree = parse_tree +flatten_tree tree +print_tree tree +delete_tree tree diff --git a/challenge-094/paulo-custodio/c/ch-1.c b/challenge-094/paulo-custodio/c/ch-1.c new file mode 100644 index 0000000000..13b70c9020 --- /dev/null +++ b/challenge-094/paulo-custodio/c/ch-1.c @@ -0,0 +1,168 @@ +/* +Challenge 094 + +TASK #1 › Group Anagrams +Submitted by: Mohammad S Anwar +You are given an array of strings @S. + +Write a script to group Anagrams together in any random order. + +An Anagram is a word or phrase formed by rearranging the letters of a +different word or phrase, typically using all the original letters exactly +once. + +Example 1: + Input: ("opt", "bat", "saw", "tab", "pot", "top", "was") + Output: [ ("bat", "tab"), + ("saw", "was"), + ("top", "pot", "opt") ] +Example 2: + Input: ("x") + Output: [ ("x") ] +*/ + +#include <memory.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +// check memory allocation +void* check_mem(void* p) { + if (!p) { + fputs("out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + + +// list of strings +typedef struct ListNode { + char* str; + struct ListNode* next; +} ListNode; + +typedef struct StrList { + ListNode* head, *tail; +} StrList; + +StrList* strlist_alloc() { + return check_mem(calloc(1, sizeof(StrList))); +} + +void strlist_free(StrList* list) { + if (list) { + ListNode* node = list->head; + while (node) { + ListNode* next = node->next; + free(node->str); + free(node); + node = next; + } + free(list); + } +} + +void strlist_push(StrList* list, const char* str) { + ListNode* node = check_mem(calloc(1, sizeof(ListNode))); + node->str = check_mem(strdup(str)); + if (!list->head) { + list->head = list->tail = node; + } + else { + list->tail->next = node; + list->tail = node; + } +} + +void strlist_print(StrList* list) { + printf("("); + for (ListNode* node = list->head; node; node = node->next) + printf("\"%s\"%s", node->str, node->next ? ", " : ""); + printf(")"); +} + + +// map of strings to list of strings +typedef struct TreeNode { + char* key; + struct TreeNode* left, *right; + StrList* strs; +} TreeNode; + +TreeNode* tree_alloc() { + return NULL; +} + +TreeNode* tree_add_key(TreeNode** proot, const char* key) { + if (*proot == NULL) { + TreeNode* node = check_mem(calloc(1, sizeof(TreeNode))); + node->key = check_mem(strdup(key)); + node->strs = strlist_alloc(); + *proot = node; + return node; + } + else { + TreeNode* node = *proot; + int cmp = strcmp(key, node->key); + if (cmp < 0) + return tree_add_key(&node->left, key); + else if (cmp > 0) + return tree_add_key(&node->right, key); + else + return node; + } +} + +void tree_free(TreeNode* node) { + if (node) { + tree_free(node->left); + tree_free(node->right); + free(node->key); + strlist_free(node->strs); + free(node); + } +} + +void tree_node_print(TreeNode* node, bool* is_first) { + if (node) { + tree_node_print(node->left, is_first); + if (!*is_first) + printf(",\n "); + strlist_print(node->strs); + *is_first = false; + tree_node_print(node->right, is_first); + } +} + +void tree_print(TreeNode* tree) { + bool is_first = true; + printf("[ "); + tree_node_print(tree, &is_first); + printf(" ]\n"); +} + +int cmp_char(const void* a, const void* b) { + return *(const char*)a - *(const char*)b; +} + +char* make_key(const char* str) { + char* key = check_mem(strdup(str)); + qsort(key, strlen(key), 1, cmp_char); + return key; +} + +int main(int argc, char* argv[]) { + TreeNode* tree = tree_alloc(); + + for (int i = 1; i < argc; i++) { + char* key = make_key(argv[i]); + TreeNode* node = tree_add_key(&tree, key); + strlist_push(node->strs, argv[i]); + free(key); + } + + tree_print(tree); + tree_free(tree); +} diff --git a/challenge-094/paulo-custodio/c/ch-2.c b/challenge-094/paulo-custodio/c/ch-2.c new file mode 100644 index 0000000000..90a3267260 --- /dev/null +++ b/challenge-094/paulo-custodio/c/ch-2.c @@ -0,0 +1,200 @@ +/* +Challenge 094 + +TASK #2 › Binary Tree to Linked List +Submitted by: Mohammad S Anwar +You are given a binary tree. + +Write a script to represent the given binary tree as an object and flatten +it to a linked list object. Finally print the linked list object. + +Example: + Input: + + 1 + / \ + 2 3 + / \ + 4 5 + / \ + 6 7 + + Output: + + 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3 +*/ + +#include <assert.h> +#include <ctype.h> +#include <memory.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MAXLINE 256 + +// check memory allocation +void* check_mem(void* p) { + if (!p) { + fputs("out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +// tree object +typedef struct Tree { + int value; + struct Tree* left, * right; +} Tree; + +// input image +char** lines; +size_t num_lines; + + +// create and delete a tree +Tree* tree_new() { + Tree* node = check_mem(calloc(1, sizeof(Tree))); + return node; +} + +void tree_delete(Tree* node) { + if (node->left) tree_delete(node->left); + if (node->right) tree_delete(node->right); + free(node); +} + +// read lines from stdin +void lines_read() { + char line[MAXLINE]; + while (fgets(line, sizeof(line), stdin)) { + lines = check_mem(realloc(lines, (num_lines + 1) * sizeof(char*))); + lines[num_lines] = check_mem(strdup(line)); + num_lines++; + } +} + +void lines_delete() { + if (lines) { + for (size_t i = 0; i < num_lines; i++) + free(lines[i]); + free(lines); + } +} + +// parse the tree +Tree* parse_subtree(int row, int col) { + // parse root + Tree* node = tree_new(); + assert(isdigit(lines[row][col])); + node->value = lines[row][col] - '0'; + + // parse children + if (row + 2 < (int)num_lines) { + // parse left subtree + if (col - 2 >= 0 && lines[row + 1][col - 1] == '/') + node->left = parse_subtree(row + 2, col - 2); + // parse right subtree + if (col + 2 < (int)strlen(lines[row + 2]) && lines[row + 1][col + 1] == '\\') + node->right = parse_subtree(row + 2, col + 2); + } + return node; +} + +Tree* parse_tree() { + assert(num_lines > 0); + char* p = strpbrk(lines[0], "0123456789"); + assert(p); + int col = p - lines[0]; + return parse_subtree(0, col); +} + +/* +// compute tree depth +void subtree_depth(Tree* node, int cur_depth, int* pmax_depth) { + if (!node) + return; + if (node->left) + subtree_depth(node->left, cur_depth + 1, pmax_depth); + if (node->right) + subtree_depth(node->right, cur_depth + 1, pmax_depth); + if (cur_depth > *pmax_depth) + *pmax_depth = cur_depth; +} + +int tree_depth(Tree* root) { + int max_depth = 0; + subtree_depth(root, 1, &max_depth); + return max_depth; +} + +// print a tree +void print_subtree(Tree* node, char* lines[], int row, int col) { + if (!node) + return; + lines[row][col] = '0' + node->value; + if (node->left) { + lines[row + 1][col - 1] = '/'; + print_subtree(node->left, lines, row + 2, col - 2); + } + if (node->right) { + lines[row + 1][col + 1] = '\\'; + print_subtree(node->right, lines, row + 2, col + 2); + } +} + +void print_tree(Tree* root) { + // create canvas + int depth = tree_depth(root); + int num_lines = depth * 2; + int num_cols = depth * 5; + char** lines = check_mem(calloc(num_lines, sizeof(char*))); + for (int i = 0; i < num_lines; i++) { + lines[i] = check_mem(calloc(num_cols + 1, 1)); + memset(lines[i], ' ', num_cols); + lines[i][num_cols] = '\0'; + } + + // draw tree + print_subtree(root, lines, 0, num_cols / 2); + + // print tree + for (int i = 0; i < num_lines; i++) + printf("%s\n", lines[i]); + + // delete canvas + for (int i = 0; i < num_lines; i++) + free(lines[i]); + free(lines); +} +*/ + +// pre-order traversal, set left to NULL, move subtree to right +Tree* flatten(Tree* root) { + if (!root) return root; + Tree* left = flatten(root->left); + Tree* right = flatten(root->right); + + root->left = NULL; + root->right = left; + + Tree* node = root; + while (node->right) // find right-most node + node = node->right; + node->right = right; + + return root; +} + +int main() { + lines_read(); + Tree* tree = parse_tree(); + flatten(tree); + + for (Tree* node = tree; node; node = node->right) + printf("%d%s", node->value, node->right ? " -> " : "\n"); + + tree_delete(tree); + lines_delete(); +} diff --git a/challenge-094/paulo-custodio/cpp/ch-1.cpp b/challenge-094/paulo-custodio/cpp/ch-1.cpp new file mode 100644 index 0000000000..f3aa6ac58d --- /dev/null +++ b/challenge-094/paulo-custodio/cpp/ch-1.cpp @@ -0,0 +1,71 @@ +/* +Challenge 094 + +TASK #1 › Group Anagrams +Submitted by: Mohammad S Anwar +You are given an array of strings @S. + +Write a script to group Anagrams together in any random order. + +An Anagram is a word or phrase formed by rearranging the letters of a +different word or phrase, typically using all the original letters exactly +once. + +Example 1: + Input: ("opt", "bat", "saw", "tab", "pot", "top", "was") + Output: [ ("bat", "tab"), + ("saw", "was"), + ("top", "pot", "opt") ] +Example 2: + Input: ("x") + Output: [ ("x") ] +*/ + +#include <algorithm> +#include <iostream> +#include <list> +#include <map> +#include <string> + +std::string make_key(const std::string& str) { + std::string out{ str }; + std::sort(out.begin(), out.end()); + return out; +} + +int main(int argc, char* argv[]) { + std::map<std::string, std::list<std::string>> map; // maps keys to lists of words + + for (int i = 1; i < argc; i++) { + auto key = make_key(argv[i]); + auto found = map.find(key); + if (found == map.end()) { // not found, create new item + std::list<std::string> list; + list.push_back(argv[i]); + map[key] = list; + } + else { // append to existing item + found->second.push_back(argv[i]); + } + } + + std::cout << "[ "; + bool first1 = true; + for (auto& it1 : map) { + if (!first1) + std::cout << "," << std::endl << " "; + first1 = false; + + std::cout << "("; + bool first2 = true; + for (auto& it2 : it1.second) { + if (!first2) + std::cout << ", "; + first2 = false; + + std::cout << "\"" << it2 << "\""; + } + std::cout << ")"; + } + std::cout << " ]" << std::endl; +} diff --git a/challenge-094/paulo-custodio/cpp/ch-2.cpp b/challenge-094/paulo-custodio/cpp/ch-2.cpp new file mode 100644 index 0000000000..6177ee537f --- /dev/null +++ b/challenge-094/paulo-custodio/cpp/ch-2.cpp @@ -0,0 +1,156 @@ +/* +Challenge 094 + +TASK #2 › Binary Tree to Linked List +Submitted by: Mohammad S Anwar +You are given a binary tree. + +Write a script to represent the given binary tree as an object and flatten +it to a linked list object. Finally print the linked list object. + +Example: + Input: + + 1 + / \ + 2 3 + / \ + 4 5 + / \ + 6 7 + + Output: + + 1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3 +*/ + +#include <exception> +#include <stdexcept> +#include <iostream> +#include <string> +#include <vector> +#include <cctype> + +// input image object +class InputImage { +public: + void append_line(const std::string& line); + void clear(); + char ch(int row, int col) const; + int root_col() const; + +private: + std::vector<std::string> m_lines; +}; + +void InputImage::append_line(const std::string& line) { + m_lines.push_back(line); +} + +void InputImage::clear() { + m_lines.clear(); +} + +char InputImage::ch(int row, int col) const { + // check if out of bounds + if (row < 0 || row >= static_cast<int>(m_lines.size()) || + col < 0 || col >= static_cast<int>(m_lines[row].size())) + return ' '; + else + return m_lines[row][col]; +} + +int InputImage::root_col() const { + if (m_lines.empty()) + throw std::invalid_argument("malformed image"); + for (int col = 0; col < static_cast<int>(m_lines[0].size()); col++) { + if (isdigit(m_lines[0][col])) + return col; + } + throw std::invalid_argument("malformed image"); +} + +// tree object +class Tree { +public: + Tree(int value = 0); + ~Tree(); + + int value; + Tree* left, * right; + + static Tree* parse(const InputImage& image); + static Tree* flatten(Tree* root); + +private: + static Tree* parse_subtree(const InputImage& image, int row, int col); +}; + +Tree::Tree(int value_) + : value(value_), left(nullptr), right(nullptr) +{} + +Tree::~Tree() { + if (left) delete left; + if (right) delete right; +} + +Tree* Tree::parse(const InputImage& image) { + int col = image.root_col(); + return parse_subtree(image, 0, col); +} + +Tree* Tree::parse_subtree(const InputImage& image, int row, int col) { + // parse root + int value = image.ch(row, col) - '0'; + if (value < 0 || value>9) + throw std::invalid_argument("malformed image"); + Tree* node = new Tree(value); + + // parse left subtree + if (image.ch(row + 1, col - 1) == '/') + node->left = parse_subtree(image, row + 2, col - 2); + // parse right subtree + if (image.ch(row + 1, col + 1) == '\\') + node->right = parse_subtree(image, row + 2, col + 2); + + return node; +} + +Tree* Tree::flatten(Tree* root) { + if (!root) return root; + Tree* left = flatten(root->left); + Tree* right = flatten(root->right); + + root->left = NULL; + root->right = left; + + Tree* node = root; + while (node->right) // find right-most node + node = node->right; + node->right = right; + + return root; +} + +// read input from stdin +void read_lines(InputImage& image) { + image.clear(); + std::string line; + while (!std::getline(std::cin, line).eof()) + image.append_line(line); +} + +int main(int argc, char* argv[]) { + InputImage image; + read_lines(image); + Tree* tree = Tree::flatten(Tree::parse(image)); + + for (Tree* node = tree; node; node = node->right) { + if (node != tree) + std::cout << " -> "; + std::cout << node->value; + } + std::cout << std::endl; + delete tree; +} diff --git a/challenge-094/paulo-custodio/forth/ch-1.fs b/challenge-094/paulo-custodio/forth/ch-1.fs new file mode 100644 index 0000000000..4f97a88525 --- /dev/null +++ b/challenge-094/paulo-custodio/forth/ch-1.fs @@ -0,0 +1,257 @@ +#! /usr/bin/env gforth + +\ Challenge 094 +\ +\ TASK #1 › Group Anagrams +\ Submitted by: Mohammad S Anwar +\ You are given an array of strings @S. +\ +\ Write a script to group Anagrams together in any random order. +\ +\ An Anagram is a word or phrase formed by rearranging the letters of a +\ different word or phrase, typically using all the original letters exactly +\ once. +\ +\ Example 1: +\ Input: ("opt", "bat", "saw", "tab", "pot", "top", "was") +\ Output: [ ("bat", "tab"), +\ ("saw", "was"), +\ ("top", "pot", "opt") ] +\ Example 2: +\ Input: ("x") +\ Output: [ ("x") ] + +\ ----------------------------------------------------------------------------- +\ counted strings + +\ compare two counted strings +: cstr= ( c-addr1 c-addr2 -- f ) + >R COUNT R> COUNT STR= +; + +\ copy string as counted string to pad +: str>pad ( addr len -- ) + DUP PAD C! + PAD 1+ SWAP CMOVE +; + +\ allot string as counted string +: cstr, ( addr len -- ) + DUP C, >R \ store length + HERE R@ CMOVE \ copy string + R> ALLOT \ advance HERE + ALIGN +; + +\ ----------------------------------------------------------------------------- +\ Linked list of strings + +\ create a new string list +: new_strlist ( -- list-addr ) + HERE 0 , 0 , +; + +: strlist.head ( list-addr -- head-addr ) +; + +: strlist.tail ( list-addr -- tail-addr ) + 1 CELLS + +; + +\ create a new node for a string list +: new_strnode ( addr len -- node-addr ) + HERE >R ( R:node-addr ) + 0 , \ store next pointer + cstr, \ store string + R> ( node-addr ) +; + +: strnode.next ( node-addr -- next-addr ) +; + +: strnode.cstring ( node-addr -- cstring-addr ) + 1 CELLS + +; + +\ push a string to the end of the list +: strlist.push { addr len list-addr -- } + addr len new_strnode ( node-addr ) + list-addr strlist.head @ 0= IF \ list is empty + DUP list-addr strlist.head ! + list-addr strlist.tail ! + ELSE + DUP + list-addr strlist.tail @ ( new-node last-node ) + strnode.next ! \ store node in next of last node + list-addr strlist.tail ! \ point tail to node + THEN +; + +: strlist.print-sep ( first -- first ) + DUP IF + DROP 0 + ELSE + ." , " + THEN +; + + +: strlist.print ( list-addr -- ) + 1 SWAP ( first list-addr ) + '(' EMIT + strlist.head @ ( first node-addr ) + BEGIN DUP 0<> WHILE \ while pointer not null + SWAP strlist.print-sep SWAP + '"' EMIT + DUP strnode.cstring COUNT TYPE + '"' EMIT + strnode.next @ + REPEAT + ')' EMIT + 2DROP +; + +\ ----------------------------------------------------------------------------- +\ map of string to linked list of strings + +\ create new map +: new_map ( -- map-addr ) + HERE 0 , 0 , +; + +: map.head ( map-addr -- head-addr ) +; + +: map.tail ( map-addr -- tail-addr ) + 1 CELLS + +; + +\ create a new node for a map +: new_mapnode ( addr len -- node-addr ) + HERE >R ( R:node-addr ) + 0 , \ store next pointer + new_strlist DROP \ store list of string values + cstr, \ store key string + R> ( node-addr ) +; + +: mapnode.next ( node-addr -- next-addr ) +; + +: mapnode.strlist ( node-addr -- strlist-addr ) + 1 CELLS + +; + +: mapnode.key ( node-addr -- cstring-addr ) + 3 CELLS + +; + +: map.add_first ( node-addr map-addr -- ) + 2DUP + map.head ! + map.tail ! +; + +: map.append { node-addr map-addr -- } + node-addr map-addr map.tail @ mapnode.next ! \ point next of last to node + node-addr map-addr map.tail ! \ point tail to node +; + +: map.find_node ( map-addr -- node-addr|0 ) \ find node with key in PAD + map.head @ ( nope-addr ) + BEGIN DUP 0<> WHILE + DUP mapnode.key PAD cstr= IF \ same key? + EXIT ( node-addr ) \ of found key + THEN + mapnode.next @ \ point to next + REPEAT + ( 0 ) \ entry not found +; + +\ add/search a key to a map, return strlist +: map.add_key { addr len map-addr -- node-strlist } + addr len str>pad \ save key in PAD + map-addr map.head @ 0= IF \ map is empty + PAD COUNT new_mapnode ( node-addr ) + DUP map-addr map.add_first \ add first entry + mapnode.strlist ( node-strlist ) + ELSE + map-addr map.find_node ( node-addr|0 ) + ?DUP IF + mapnode.strlist ( node-strlist ) + ELSE + PAD COUNT new_mapnode ( node-addr ) + DUP map-addr map.append \ append node + mapnode.strlist ( node-strlist ) + THEN + THEN +; + +: map.print-sep ( first -- first ) + DUP IF + DROP 0 + ELSE + ',' EMIT CR 2 SPACES + THEN +; + +: map.print ( map-addr -- ) + 1 SWAP ( first map-addr ) + ." [ " + map.head @ ( first node-addr ) + BEGIN DUP 0<> WHILE + SWAP map.print-sep SWAP ( node-addr )< |
