markuspeloquin

https://leetcode.com/problems/word-search-ii/

Feb 1st, 2021
425
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.54 KB | None | 0 0
  1. struct Trie {
  2.     Trie() : word(false), parent(nullptr), children(26) {}
  3.  
  4.     ~Trie() {
  5.         for (Trie *n : children)
  6.             delete n;
  7.     }
  8.  
  9.     void add(const string &s, int pos=0) {
  10.         if (pos == s.length())
  11.             word = true;
  12.         else {
  13.             int code = to_code(s[pos]);
  14.             if (code == -1) {
  15.                 // could skip ?
  16.                 //add(s, pos + 1);
  17.                 ostringstream out;
  18.                 out << "bad char at " << pos << ": s";
  19.                 throw runtime_error(out.str());
  20.             } else {
  21.                 if (!children[code]) {
  22.                     children[code] = new Trie;
  23.                     children[code]->parent = this;
  24.                 }
  25.                 children[code]->add(s, pos + 1);
  26.             }
  27.         }
  28.     }
  29.    
  30.     void remove() {
  31.         if (!word) return;
  32.         word = false;
  33.        
  34.         for (Trie *child : children) {
  35.             if (child)
  36.                 return;  
  37.         }
  38.        
  39.         // not any child; detach from parent if there is one
  40.         if (parent)
  41.             parent->detach(this);
  42.         delete this;
  43.     }
  44.  
  45.     Trie *next(char c) {
  46.         return children[to_code(c)];
  47.     }
  48.  
  49.     bool word;
  50.     Trie *parent;
  51.     vector<Trie *> children;
  52.  
  53. private:
  54.     static int to_code(char c) {
  55.         return ('A' <= c && c <= 'Z') ? c - 'A' :
  56.             ('a' <= c && c <= 'z') ? c - 'a' :
  57.             -1;
  58.     }
  59.    
  60.     void detach(Trie *child) {
  61.         bool any_child = false;
  62.         for (int i = 0; i < children.size(); i++) {
  63.             if (children[i]) {
  64.                 if (children[i] == child)
  65.                     children[i] = nullptr;
  66.                 else
  67.                     any_child = true;
  68.             }
  69.         }
  70.        
  71.         /*
  72.          * XXX This doesn't work if too much is removed.
  73.          * Tombstoning would work, though.
  74.          * Flag for deletion, then the recursion caller checks if it's been deleted yet.
  75.          *
  76.          * // not any child; detach from parent if there is one
  77.          * if (!any_child && parent) {
  78.          *     parent->detach(this);
  79.          *     delete this;
  80.          * }
  81.          */
  82.     }
  83. };
  84.  
  85. class Solution {
  86. public:
  87.     vector<string> findWords(const vector<vector<char>> &board, const vector<string> &words) {
  88.         return find_words_TRIE(board, words);
  89.         //return find_words_RANGE(board, words);
  90.     }
  91.    
  92.     /*
  93.      * RANGE-BASED SOLUTION
  94.      */
  95.    
  96.     vector<string> find_words_RANGE(
  97.         const vector<vector<char>> &board, vector<string> words
  98.     ) {
  99.         sort(words.begin(), words.end());
  100.        
  101.         vector<vector<uint8_t>> visited(board.size(), vector<uint8_t>(board[0].size()));
  102.         string word;
  103.        
  104.         unordered_set<string> found;
  105.         for (int i = 0; i < board.size(); i++) {
  106.             for (int j = 0; j < board[i].size(); j++) {
  107.                 find_words_from_RANGE(
  108.                     board, words, visited, word, {i, j}, {0, words.size()}, found
  109.                 );
  110.             }
  111.         }
  112.         vector<string> out(found.begin(), found.end());
  113.         sort(out.begin(), out.end());
  114.         return out;
  115.     }
  116.    
  117.     pair<int, int> sub_range(
  118.         const vector<string> &words, pair<int, int> range, char ch, int pos
  119.     ) {
  120.         auto [lo, hi] = range;
  121.        
  122.         // find lower_bound
  123.         while (lo < hi) {
  124.             int mid = (lo + hi) / 2;
  125.             if (words[mid][pos] < ch)
  126.                 lo = mid + 1;
  127.             else
  128.                 hi = mid;
  129.         }
  130.         int lower = lo;
  131.        
  132.         // find upper_bound
  133.         hi = range.second;
  134.         while (lo < hi) {
  135.             int mid = (lo + hi) / 2;
  136.             if (words[mid][pos] <= ch)
  137.                 lo = mid + 1;
  138.             else
  139.                 hi = mid;
  140.         }
  141.         int upper = hi;
  142.         return {lower, upper};
  143.     }
  144.    
  145.     void find_words_from_RANGE(
  146.         const vector<vector<char>> &board,
  147.         const vector<string> &words,
  148.         // state of recursion
  149.         vector<vector<uint8_t>> &visited,
  150.         string &word,
  151.         pair<int, int> loc,
  152.         pair<int, int> prev_range,
  153.         // output
  154.         unordered_set<string> &out
  155.     ) {
  156.         // visit loc
  157.         char ch = board[loc.first][loc.second];
  158.         pair<int, int> range = sub_range(words, prev_range, ch, word.length());
  159.         if (range.first == range.second)
  160.             return;
  161.        
  162.         visited[loc.first][loc.second] = 1;
  163.         word += ch;
  164.         for (int r = loc.first - 1; r < loc.first + 2; r++) {
  165.             if (r < 0 || r >= board.size())
  166.                 continue;
  167.             for (int c = loc.second - 1; c < loc.second + 2; c++) {
  168.                 if (c < 0 || c >= board[r].size())
  169.                     continue;
  170.                 // don't allow repeats or [r,c]==loc
  171.                 if (visited[r][c])
  172.                     continue;
  173.                 // no diagonals:
  174.                 if (r != loc.first && c != loc.second)
  175.                     continue;
  176.                 find_words_from_RANGE(
  177.                     board, words,
  178.                     visited, word, {r, c}, range,
  179.                     out
  180.                 );
  181.             }
  182.         }
  183.         if (words[range.first].length() == word.length())
  184.             out.insert(word);
  185.         word.erase(word.length() - 1);
  186.         visited[loc.first][loc.second] = 0;
  187.     }
  188.    
  189.     /*
  190.      * TRIE-BASED SOLUTION
  191.      */
  192.    
  193.     vector<string> find_words_TRIE(
  194.         const vector<vector<char>>& board, const vector<string>& words
  195.     ) {
  196.         Trie dict;
  197.         for (auto &word : words)
  198.             dict.add(word);
  199.        
  200.         vector<vector<uint8_t>> visited(board.size(), vector<uint8_t>(board[0].size()));
  201.         string word;
  202.        
  203.         vector<string> out;
  204.         for (int i = 0; i < board.size(); i++) {
  205.             for (int j = 0; j < board[i].size(); j++) {
  206.                 find_words_from_TRIE(
  207.                     board,
  208.                     visited, word, {i, j}, &dict,
  209.                     out
  210.                 );
  211.             }
  212.         }
  213.         sort(out.begin(), out.end());
  214.         return out;
  215.     }
  216.    
  217.     void find_words_from_TRIE(
  218.         const vector<vector<char>> &board,
  219.         // state of recursion
  220.         vector<vector<uint8_t>> &visited,
  221.         string &word,
  222.         pair<int, int> loc,
  223.         Trie *prev_cursor,
  224.         // output
  225.         vector<string> &out
  226.     ) {
  227.         // visit loc
  228.         char ch = board[loc.first][loc.second];
  229.         Trie *cursor = prev_cursor->next(ch);
  230.         if (!cursor)
  231.             return;
  232.        
  233.         visited[loc.first][loc.second] = 1;
  234.         word += ch;
  235.         for (int r = loc.first - 1; r < loc.first + 2; r++) {
  236.             if (r < 0 || r >= board.size())
  237.                 continue;
  238.             for (int c = loc.second - 1; c < loc.second + 2; c++) {
  239.                 if (c < 0 || c >= board[r].size())
  240.                     continue;
  241.                 // don't allow repeats or [r,c]==loc
  242.                 if (visited[r][c])
  243.                     continue;
  244.                 // no diagonals:
  245.                 if (r != loc.first && c != loc.second)
  246.                     continue;
  247.                 find_words_from_TRIE(board, visited, word, {r, c}, cursor, out);
  248.             }
  249.         }
  250.         if (cursor->word) {
  251.             out.push_back(word);
  252.             //cursor->word = false;
  253.             cursor->remove();
  254.         }
  255.         word.erase(word.length() - 1);
  256.         visited[loc.first][loc.second] = 0;
  257.     }
  258. };
Add Comment
Please, Sign In to add comment