runnig

Word Ladder 2 (all paths)

Feb 17th, 2013
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.02 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <utility>
  4. #include <unordered_set>
  5. #include <unordered_map>
  6. #include <string>
  7. #include <vector>
  8. #include <deque>
  9. #include <functional>
  10. #include <stdint.h>
  11.  
  12. using namespace std;
  13.  
  14. typedef unordered_set<string> dict_t;
  15.  
  16. typedef size_t hash_t;
  17. typedef pair<hash_t, int> partial_hash_t; // hash computed with ith character skipped
  18. typedef unordered_set<int> word_bucket_t; // a set of word indices with the same partial hash
  19.  
  20. typedef vector<string> path_t;
  21. typedef vector<path_t> allpaths_t;
  22.  
  23. template<typename T>
  24. inline void hash_combine(hash_t & H, const T v)
  25. {
  26.     std::hash<T> hash_fn; // standard hash function
  27.     H ^= hash_fn(v) + 0x9e3779b9 + (H<<6) + (H>>2);
  28. }
  29.  
  30. // hash function for partial hash
  31. class phash_fn {
  32. public:
  33.     size_t operator ()(const partial_hash_t &v) const
  34.     {
  35.         hash_t H = 0;
  36.         hash_combine(H, v.first);
  37.         hash_combine(H, v.second);
  38.         return H;
  39.     }
  40. };
  41.  
  42. class phash_eq{
  43. public:
  44.     bool operator ()(const partial_hash_t &a, const partial_hash_t &b) const
  45.     {
  46.         return a.first == b.first && a.second == b.second;
  47.     }
  48. };
  49.  
  50. // lets put words with same partial hashes into same word bucket
  51. typedef unordered_map<partial_hash_t, word_bucket_t, phash_fn, phash_eq> bucket_table_t;
  52.  
  53. typedef uint16_t vertex_t;
  54.  
  55. typedef unordered_map<int, word_bucket_t> graph_t;
  56.  
  57. hash_t str_hash(const string & s, const size_t len)
  58. {
  59.     hash_t H = 0;
  60.     for(size_t i = 0; i < len; ++i)
  61.     {
  62.         hash_combine(H, s[i]);
  63.     }
  64.     return H;
  65. }
  66.  
  67.  
  68. hash_t str_hash(const string & s, size_t skip_pos, const size_t len)
  69. {
  70.     hash_t H = 0;
  71.     for(size_t i =0; i < len; ++i)
  72.     {
  73.         if(i != skip_pos)
  74.         {
  75.             hash_combine(H, s[i]);
  76.         }
  77.     }
  78.     return H;
  79. }
  80.  
  81. class Solution {
  82. public:
  83.     vector<string> word_vec;
  84.     vector<hash_t> full_hashes;
  85.  
  86.     void compute_hashes(vector<hash_t>& hashes,
  87.         const string & word, const size_t word_len)
  88.     {
  89.         // reset hashes for the current word
  90.         hashes.resize(word_len, 0);
  91.  
  92.         for(size_t hash_no = 0; hash_no < word_len; ++hash_no)
  93.         {
  94.             // skip character #hash_no when updating hash[hash_no]
  95.             hashes[hash_no] = str_hash(word, hash_no, word_len);
  96.         }
  97.     }
  98.  
  99.     void connect_graph(graph_t & G, bucket_table_t & wordbuckets,
  100.         const vector<hash_t> & full_hashes)
  101.     {
  102.         // check all the bucket within the same bucket
  103.         for(bucket_table_t::iterator it = wordbuckets.begin(); it != wordbuckets.end(); ++it)
  104.         {
  105.             word_bucket_t & bucket = it->second;
  106.             word_bucket_t::iterator w1, w2, e = bucket.end();
  107.  
  108.             for(w1 = bucket.begin(); w1 != e; ++w1)
  109.             {
  110.                 for(w2 = w1; w2 != e; ++w2)
  111.                 {
  112.                     if(w1 == w2) { continue; }
  113.  
  114.                     const size_t word1_pos = *w1, word2_pos = *w2;
  115.  
  116.                     // don't connect word with itself (when 'start' matches
  117.                     if(word1_pos != word2_pos && full_hashes[word1_pos] != full_hashes[word2_pos] )
  118.                     {
  119.                         G[word1_pos].insert(word2_pos);
  120.                         G[word2_pos].insert(word1_pos);
  121.                     }
  122.                 }
  123.             }
  124.         }
  125.     }
  126.  
  127.     allpaths_t ladderLength(string start, string end, dict_t &dict)
  128.     {  
  129.         const size_t WORD_LEN = start.size();
  130.  
  131.         bool start_in_dict = (dict.find(start) != dict.end());
  132.         bool end_in_dict = (dict.find(end) != dict.end());
  133.  
  134.         // modify start and end so that
  135.         // their full hashes are different from words in dict
  136.         start += '^';
  137.         end += '$';
  138.  
  139.         dict.insert(start);
  140.         dict.insert(end);
  141.  
  142.         const size_t NUM_WORDS = dict.size();
  143.  
  144.         word_vec.resize(NUM_WORDS);
  145.  
  146.         size_t start_pos = INT_MAX, end_pos = INT_MAX;
  147.  
  148.         full_hashes.resize(NUM_WORDS, 0);
  149.        
  150.  
  151.         bucket_table_t wordbuckets;
  152.         vector<hash_t> partial_hashes;
  153.  
  154.         // for all the words in the dictionary
  155.         dict_t::iterator w = dict.begin();
  156.         for(size_t word_no = 0; w != dict.end(); ++w, ++word_no)
  157.         {
  158.             const string & word = *w;
  159.  
  160.             hash_t full_hash = str_hash(word, WORD_LEN);
  161.  
  162.             // compute partial hashes for all partial strings
  163.             // ith partial string is the original string with ith character skipped
  164.             compute_hashes(partial_hashes, word, WORD_LEN);
  165.  
  166.             // put all words that are different by only one character
  167.             // into wordbuckets of words
  168.             for(size_t hash_no = 0; hash_no < WORD_LEN; ++hash_no)
  169.             {
  170.                 const hash_t & H = partial_hashes[hash_no];
  171.                 wordbuckets[make_pair(H, hash_no)].insert(word_no);
  172.             }
  173.  
  174.  
  175.             if(start_pos == INT_MAX && word == start) { start_pos = word_no; }
  176.             if(end_pos == INT_MAX && word == end) { end_pos = word_no; }
  177.  
  178.             word_vec[word_no] = word;
  179.             full_hashes[word_no] = full_hash;
  180.         }
  181.  
  182.         graph_t G;
  183.  
  184.         connect_graph(G, wordbuckets, full_hashes);
  185.  
  186.         graph_t::iterator g;
  187.  
  188.         allpaths_t all;
  189.  
  190.         if(!start_in_dict)
  191.         {
  192.             g = G.find(start_pos);
  193.             if(g != G.end())
  194.             {  
  195.                 word_bucket_t & siblings = g->second;
  196.  
  197.                 // remove connection from start_pos to end_pos if they are connected
  198.                 // by problem definition path must go throught the graph
  199.                 word_bucket_t::iterator s = siblings.find(end_pos);
  200.                 if(s != siblings.end()) { siblings.erase(s); }
  201.  
  202.                 if(siblings.empty()) { return all; }
  203.             }
  204.             else { return all; } // no connections from 'start' to any node in the graph? exit
  205.         }
  206.  
  207.         // no connections from 'end' to any node in the graph? exit
  208.         g = G.find(end_pos);
  209.         if( g == G.end() || g->second.empty()) { return all; }
  210.  
  211.         unordered_set<vertex_t> visited;
  212.        
  213.         path_t path;
  214.         dfs(G, visited, start_pos, end_pos, WORD_LEN, all, path);
  215.         return all;
  216.     }
  217.  
  218.    
  219.  
  220.     void dfs(graph_t & G, unordered_set<vertex_t> & visited,
  221.         int vertex, int vertex_end, int word_len,
  222.         allpaths_t & all, path_t & path)
  223.     {
  224.         if(visited.find(vertex) != visited.end() ) { return; }
  225.  
  226.         visited.insert(vertex);
  227.  
  228.         const string & S = word_vec[vertex];
  229.  
  230.         path.push_back(word_vec[vertex].substr(0,word_len));
  231.  
  232.         if(vertex == vertex_end)
  233.         {          
  234.             all.push_back(path);
  235.             path.pop_back();
  236.             return;
  237.         }
  238.  
  239.         graph_t::iterator g = G.find(vertex);
  240.                
  241.         if(g != G.end())
  242.         {
  243.             word_bucket_t & siblings = g->second;
  244.             word_bucket_t::iterator sibling = siblings.begin(), end = siblings.end();
  245.        
  246.  
  247.             for(; sibling != end; ++sibling)
  248.             {
  249.                 const int v = *sibling;
  250.                 dfs(G, visited, v, vertex_end, word_len, all, path);
  251.             }
  252.         }
  253.         path.pop_back();
  254.     }
  255. };
  256.  
  257.  
  258. #define TEST 1
  259.  
  260. int _tmain(int argc, _TCHAR* argv[])
  261. {
  262.     dict_t words;
  263.     vector<vector<string> > ret;
  264.  
  265. #if TEST==1
  266.     words.insert("hot");
  267.     words.insert("dot");
  268.     words.insert("dog");
  269.     words.insert("lot");
  270.     words.insert("log");
  271.     ret = Solution().ladderLength("hit", "cog", words);
  272. #elif TEST==2
  273.     words.insert("hot");
  274.     ret = Solution().ladderLength("hot", "hot", words);
  275. #elif TEST==3
  276.     words.insert("dot");
  277.     words.insert("hot");
  278.     ret = Solution().ladderLength("hot", "hot", words);
  279.  
  280. #elif TEST==4
  281.     // ["talk","tons","fall","tail","gale","hall","negs"]
  282.     words.insert("talk");
  283.     words.insert("tons");
  284.     words.insert("fall");
  285.     words.insert("tail");
  286.     words.insert("gale");
  287.     words.insert("hall");
  288.     words.insert("negs");
  289.     ret = Solution().ladderLength("talk", "tail", words);
  290. #elif TEST==5
  291.     words.insert("a");
  292.     words.insert("b");
  293.     words.insert("c");
  294.     ret = Solution().ladderLength("a", "c", words);
  295. #endif
  296.    
  297.     return 0;
  298. }
Advertisement
Add Comment
Please, Sign In to add comment