推荐:数据科学课程和书籍清单以及培训讲座


一亩三分地论坛

 找回密码
 获取更多干活,快来注册

一亩三分地官方iOS手机应用下载
查看: 184|回复: 4
收起左侧

[算法题] 各位大神能不能帮我看看Palindrome Pairs为什么会TLE(本地运行正确)

[复制链接] |试试Instant~ |关注本帖
2011051305 发表于 2017-8-10 09:14:07 | 显示全部楼层 |阅读模式

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看,没有帐号?获取更多干活,快来注册

x
这道题有个很长的testcase (testcase附在下面  过不去,但是用leetcode run code 或者本地IDE跑都是能得到正确的结果的 (正确结果是 [] ) 。注意是不提交,只是点击leetcode的 "run code"按钮 也能得到这个结果。

实在是想不到哪里能有问题,唯一想到的是建trie的时候分配memory手动分配咋stack而不是heap上,这个方法当时在concatenate words的时候 看到discussion李提到过,但是我没看懂。。。(醉了)。。

我的思路就是分别建前缀树和后缀树。后缀树是每个单词的reverse。然后针对words中的每个单词,看这个单词是不是新组合单词的前缀(新组合单词的后缀就是从后缀树找到以但这个单词为前缀的所有单词), or 看这个单词是不是新组合的后缀。

各位大大怎么看~~
  1. #define CHILDSIZE 26
  2. class TrieNode{
  3. public:
  4.     TrieNode * children[CHILDSIZE];
  5.     bool isWord;
  6.     TrieNode(): isWord(false){
  7.         for (auto & child : children){
  8.             child = nullptr;
  9.         }
  10.     }
  11. };

  12. class Trie{
  13. public:
  14.     TrieNode * root;
  15.     Trie(){
  16.         root = new TrieNode();
  17.     }
  18.     ~Trie(){
  19.         for (int i = 0; i < CHILDSIZE; ++i){
  20.             delete this->root->children[i];
  21.         }
  22.     }
  23.     void insert(string word) {
  24.         TrieNode * curr = root;
  25.         for (int i = 0; i < word.size(); ++i){
  26.             //每次判断这个节点是否存在,如果不存在则创建一个
  27.             if (!curr->children[word[i]-'a']){
  28.                 curr->children[word[i]-'a'] = new TrieNode();
  29.             }
  30.             curr = curr->children[word[i]-'a'];
  31.         }
  32.         curr->isWord = true; // 全部插完后加bool标记
  33.     }

  34.     bool startsWith(string prefix) {
  35.         if (prefix.empty()){
  36.             return false;
  37.         }
  38.         TrieNode * curr = root;
  39.         for (int i = 0; i < prefix.size(); ++i){
  40.             if (curr->children[prefix[i]-'a'] == nullptr){
  41.                 return false;
  42.             }
  43.             curr = curr->children[prefix[i]-'a'];
  44.         }
  45.         //prefix每个字符都遍历完了
  46.         return true;
  47.     }
  48.     // 我们已经假设prefix是trie树的合法前缀
  49.     void findSuffix(vector<string> & res, string prefix){
  50.         TrieNode * curr = root;
  51.         for (int i = 0; i < prefix.size(); i++){
  52.             if (curr->children[prefix[i]-'a']){
  53.                 curr = curr->children[prefix[i]-'a'];
  54.             }
  55.         }
  56.         string temp = "";
  57.         for (int i = 0; i < CHILDSIZE; ++i){
  58.             if (curr->children[i]){
  59.                 TrieNode * preserved = curr;
  60.                 curr = curr->children[i];
  61.                 temp += ('a' + i);
  62.                 if (curr->isWord){
  63.                     res.push_back(prefix + temp);
  64.                 }
  65.                 findSuffix(res, prefix+temp);
  66.                 temp.pop_back();
  67.                 curr = preserved;
  68.             }
  69.         }
  70.     }
  71. };

  72. class Solution {
  73. public:
  74.     vector<vector<int>> palindromePairs(vector<string>& words) {
  75.         vector<vector<int>> res;
  76.         unordered_map<string, int > wordsMap;
  77.         if (words.empty()) return res;
  78.         bool hasEmpty = false;

  79.         // create trie
  80.         Trie * prefixTrie = new Trie();
  81.         for (int i = 0; i < words.size(); ++i){ // 正向的前缀树
  82.             prefixTrie->insert(words[i]);
  83.             wordsMap[words[i]]=i; // 构建前缀树的过程中 顺手把word:wordidx对应的map建好
  84.             if (words[i] == ""){hasEmpty = true;} // 我们认为空字符串是任何单词的前缀 也是任何单词的后缀
  85.         }
  86.         Trie * suffixTrie = new Trie();
  87.         for (string w : words){ // 反向的后缀树
  88.             reverse(w.begin(), w.end());
  89.             suffixTrie->insert(w);
  90.         }
  91.         // 查找
  92.         for (int i = 0; i < words.size(); ++i){
  93.             // 单词words[i]可能是新组合单词的前缀
  94.             if (suffixTrie->startsWith(words[i])){ //如果在后缀树里
  95.                 // 找到所有对应的单词
  96.                 vector<string> alists;
  97.                 suffixTrie->findSuffix(alists, words[i]); // 在后缀树中找到以words[i]为前缀的所有单词
  98.                 alists.push_back(words[i]); // words[i]本身也可能是后缀树的组成部分
  99.                 for (string wr : alists){
  100.                     reverse(wr.begin(), wr.end());
  101.                     string wcomb = words[i] + wr; // words[i]是新组合单词的前缀
  102.                     if (wordsMap.count(wr) && isPalindrome(wcomb)){
  103.                         int idx2 = wordsMap[wr];                     // 找对应的idx
  104.                         if (i != idx2){ //distince [i,j]
  105.                             res.push_back(vector<int>{i, idx2});
  106.                         }
  107.                     }
  108.                 }

  109.             }
  110.             // 单词words[i]可能是新组合单词的后缀
  111.             string wr = words[i];
  112.             reverse(wr.begin(), wr.end());
  113.             if (prefixTrie->startsWith(wr)){ // 如果在前缀树里
  114.                 // 找到以reverse of words[i]为前缀的所有单词
  115.                 vector<string> alists;
  116.                 prefixTrie->findSuffix(alists, wr);
  117.                 alists.push_back(wr); // words[i]本身是前缀树的一部分
  118.                 for (string w : alists){
  119.                     string wcomb = w + words[i]; // 注意这里不需要wr再reverse了! words[i]是新组合单词的前缀
  120.                     if (wordsMap.count(w) && isPalindrome(wcomb)){
  121.                         int idx2 = wordsMap[w];                     // 找对应的idx
  122.                         if (i != idx2){ //distince [i,j]
  123.                             res.push_back(vector<int>{idx2, i});
  124.                         }
  125.                     }
  126.                 }
  127.             }
  128.         }
  129.         if (hasEmpty){
  130.             int idx = wordsMap[""];
  131.             for (int i = 0; i < words.size(); ++i){
  132.                 if (i != idx && isPalindrome(words[i])){
  133.                     res.push_back(vector<int>{i,idx}); // 空字符是任何单词(如果单词本身是回文串)的后缀
  134.                     res.push_back(vector<int>{idx, i}); // 空字符是任何单词(如果单词本身是回文串)的前缀
  135.                 }
  136.             }
  137.         }
  138.         std::sort(res.begin(), res.end());
  139.         res.erase(std::unique(res.begin(), res.end()), res.end());
  140.         return res;
  141.     }
  142.     // 检查单词是不是palindrome
  143.     bool isPalindrome(string &s){
  144.         if (s.empty()){return true;}
  145.         if (s.size() <= 1){ return true;}
  146.         int left = 0, right = (int)(s.size()-1);
  147.         while (left < right){
  148.             if (s[left] == s[right]){
  149.                 left++; right--;
  150.             }
  151.             else{ return false; }
  152.         }
  153.         return true;
  154.     }
  155. };

  156. int main(){
  157.     vector<string> words = {"aba","ba","a","caba"};
  158.     vector<vector<int> > pairs = Solution().palindromePairs(words);
  159.     for (auto p: pairs){
  160.         for (auto i : p){
  161.             cout << i << " ";
  162.         }
  163.         cout << endl;
  164.     }
  165.     return 0;
  166. }
复制代码
最长的那个test case: {"bbaabaaaabbbbaaaabaaaabaabbabbbaaabbabbbabbaaababbaabbaaaabbbaabbaabaaaabaaabbaabab","babbbbbaabbbaaaaaabbbbbbbaabbabbabbbbbaababaabbabbbabbbbbbabba","bbbbaabbbababbabbbbabaababaabbaabbabaaaaabababbabbabbbbbabbbbaaaabbabbabbbabababbbaaa","ababbbbbbbaaaabbaaababbbabababbaabbaababbbabbbabaabbaabaababbbabababaaabbbbabbaa","abbbaababaaaaabababaabaaaaaabbbbbbbababaaaabaabbbaaabbaaaabbbabbbbabbaaaaaaaaaaabbaaaababbabbbabbabaaaaabbaababbabbabababaaaaabbabbababbaaaabbbababaaabbaaabbabbaaba","aabbaaaaaaabaaabbbababbbbabababaaabbbabaabbababbaabbbbbaabbbbaabaa","abbabaabbaaaaaababbbabbabababbababbbbaaaaabbbaaabbaababbababbbabbaaaabbabbbabbabaaaaaaabbabbbaababaaaabbaabaabababbaaaababbabbbabaabbabbbbaaaabbabbaabbaaaababbbbbbaaaaaababba","abbabaabbabbabbbabaabbbbbabaabbbbaabaaabaabaaabbaaaaaaababbababb","bbabbbbaaabbbbaaababbabaabbbbababaaaabbaaabbbaabbbaaabaababababaaaaabbbbaaaabbbababbabbbbaabbbbaaaaaaaaaabbabaaabaabaaa","aabaabbabbabbaaabbbbbaabbaababbabbaabbabaaaaaababaabaabbaaaabbabbbaababaaabaabbbbbaabbbbabbbbaaaaabbbbabbbbabaabaabbaabbbabaabababaabbaaaaabbabaaabbaabbbabaaaababbabbbababaaabbaa","bbbaaaaaaaabaababbabbabbbb","aabbaababbbbbbbabbbababaaaababbabaaabbaaaaabbbaaababbaaabbaaaaaaabbaabbaababbbbaabbaababbabbbbbbaaabaaaabbaabaababaabaab","aabbaabaabbabaabbbababbbaababbaaaababaaaaabaaaababbabbabababaaaabbabbbabbbbbbaababaaabbbababaabaaaabbbabaaa","aabbbbbbaabbabababbbbabbbbbaabbabaabbaaabbbb","ababbabaaabaaa","babbaaaaabbaaabaaaabaabaabaaabaaaaaaabaaabba","bababaabbaaaaababbabaaabbbabababbbbbabbbbababb","aaababbbbaabaabaaaabaabbabbababaaaaab","baabbbbbaabbaaaaababbabaabbabaaaabbabbbaabbabababababbaabaaabbbaabaabbbabbaaabbbbabababaabaabaabaabbbaaabaaabbbaaabaaaabbaaabbaaaababbbbabbaabbababbaabbbbbbababaaaabbbababa","baabbabaabaababbbaababbbbbabbbabbaaaaaaaabbbaabbaabaabbbabaabaabaabbaaabaaaabaaabaababaa","bbabbbabaababaabaaabbbbaaaaaabbbaaaaaaabababababbbbababbaaaaabbaabbabababbaaaabababbababbabbababbabbaa","aabbaabaabbaaabaaaaaabaaabbabababaaaabbabaabaaabbbabababbaabaaabbabbbbabbaabbababbbabbaaaabaaababbabbbbbbaaabbaababbabaabaaabaaabbbabaababaa","babaaababaabbabbabbbbbabaaabbaaabbabaabbabbabbbaabbbaaaaaabaabbaababbbbaaababbababbabbbabaababaabbabababbbabaabbbbaabaababbaa","bbabbababaaababababaabaaaaaaaabaababaababbabbabb","bbabbbbabbaaaabaabbbbbbabbbaaaaaaabbbbabbaaabbabaabbabaabbbbbbaabbbabaaabbabaaabbaba","baabbbbbbaaaaabbaabbbbabaaabbaaaabbbaaabbabaaababaababbbbbbabbaabaaabaaabbabbabaaaba","bbbaabaabbabababbaaabbaaaababaabbbbaabaaaaaaaaabbbbaabbbbabbbabababbabbbbababbaabbba","aabbbaabaababaaaabbbbabaabaabaaabababbaabbaabbaaabaababaaabbbabaaababaabbaababbbbaababaabaabbaababbababbbbbababababaabbabbaabaaaaaabaabbaabaabaaabaabba","abbabaababbbbbbaaaaaababbaabaabbaabbaaaababaababaabbbbbaaaabbbabbbbbaabbbbbbaaababbbaabaabababb","bbbaabaabaaaaabaabaabbbbaaaabaabbbbbaabbaaabbbbbababbbbabbaaaaabbaababababababbbbbbbaaabaabbbaaaaababbbaabbabaabababbbbaaabaabbababbbaabbaabbbbaaaabababbabaabbaaaaaababaaaaabaababaabbabaabbabababab","babaabaabaabbbabaaaabaabbbaaaaaaabaababbabbbaabbbabaababbabbaabbaaabaaaabaababbabbaababbabababbbabaabbbababbbbbbbaaababbaaaabaabaabbababbaaabbaabbbaaabaabaaaabaa","abbbababaaabbaabbbbabababbaabbaaaabaabaabbbbbbbbaabbbbaaaaabbbbabaaaaabbbaaaaabbbbaaaaaababbbbbaabbabaaaaabbaabaaabaababbabaabaaabbab","babaabaababababbbbabababbbaabbaaabbbaabbaaaabaaabbbbbaaaab","aaaabbaabababbbaa","bbbbabbaabaabbbbaaaaaaaabbaababaaabaaabaaabbbbaababbbaabaabbbbaaabbabaabbbbbabbbbaaabababaabbaaababbabababbbabbabaabaaaabbab","aababaabaaaaaabbabababaaaaababbbbaabaa","bbababaaaaaaaaabaabbaaaabaaaaaaaaabbbabaabbbbbabaabaaabbbabbbabbbaaaaaabaaabbbbbbaa","abbaabaaaaabbaaaaaabbbbabaabbabbaabbbabbababaabaabaaabbababbaaabaababbbbbabbbabbabbaaaabbaababbaababbbabbbbbbaaabbbbbbb","baabababbbbbaabbbabaababaababaababbbabbbbbababbaababbaaaabaaabbbbaaaababbabbbabaabaabbababaaa","abbaabbbaabbabbabbbbbbbabbbabbaaabbaaababbaabbaababab","bbabbabbbbbbabababbbabaabbbaaaabababbaabbbabbbbaababbaabaaabbbbabaaaabbbabbaaabaabbaabbbaaababbaaaabaabbabbbabbbaaabaaabbbbabbaabbaabaa","aaaabbbabbaabbababbabbabaababbababaabbaaabaaaababbbabbaaaabbbbabaaabbbaaabababbbabbaabaaabbaabbbaabbbbaaabbbaabbbbababaaaaababbbabaabbbbbbabbabbbbbabaaabaaaaaabbaa","babaaabaabbaababaaabbaaababbbbbbbaabbbbbbbbabbaabbbbbbaaaaabbaabababaabbbabaaaaaaabbaabababaaabbabbabbaababbaaabbbaaaababbbbbabbbaabbbaaaabbabbaabbbaababbaaaabbaaaababbbbbb","abaababbaaabbbaaaaababaabbab","aabbaaaababbbabbbaaabaabababbabbbaabaaaabaabaaaabbabaabbaaabbbaaabbaabbabbbbaaabbbababbaabbaaaabbbabaabbbabbbbbbbaab","aabbbabbabaaaaabbabbababbbabbbbbbbbaabbbbabbbaabaabbaaababbbaaaaabbaaabbab","baaaabababaaababbaabbbabaaabbbbabbbbaaaabbabbbbbbbbababbaaaaabaabaaabbaabbbbbabababaabbbbaabbbbbabbaabaaabaababbbabbbabaababbaaaabbaaaaaabaababbbabaabbbaaabbbabbbaabbbbbbaabbabbbbabaabbbbaba","bbbaababaabaabbabbaabbabbaabbbbabaabbabbbbbbbabbaaaaababaaabbbaba","baaaaababaabaabaabbbbabbbbbaabbaabbaaababaabaababaabbaaabbabbbabbbaababababbaaaab","baabaaababbabbbaaaabbaabbaababbaababbbaabaabaaaaaabbbbababaaabaaabaababbaabbabbaababbbbbabbabbaabbaabbbabbbaabb","bbaaaaabbbaaabbbaaaaaaaaaabaaaaa","bbbbbbabaaaaabbbbaaabbabaababaabababbabbabaabababababbaabbabbbabbbababa","bbaabbbaabbabababaaaaaabbaabbababbbbabaabbbaabbabaabbbabbbabbaaabbabbababaaabbbababbabbbbbbbbaaaaabbaa","abaabbbaabbbbaabbabaabaaabaabaaaabbabbbabbaaabbbbababaabaaabaaaaaaaabaaaababbababaabbbbbaababaabbbbabbaaabbbabbabbbbabbbbaabaaa","bababbabbaaabbabaababbbbaabaabbbbbbababaabbbbaababababbaabbaabaaaababbabbabab","baaabbabbaaababbbbbbbaabaaabbabbaaabbabababbaaaabaabbbbaaaabbabbbbbbabaaaaabaabaaaaabababbbaabbaabbabbbbbabaababababbbbbbaabbbabbbaaabaabababaabaabbbbbbbbabaaaaabbaababab","ababababababbbabbabbbbbabbabbbbabbaaabbbbbbbbbbabbaabaabbbababbabbbaaaababbaabbbaab","baaaabbababbabaabbabbaabbbbabbbabbabbbbbabaaaabaabbbabbaababbabababaaaaabaaaababbbabbbaaaaabbbabbbaaaabbbbbaaaba","baababbbaaaabbbaaababbabaababbbbbaaabaabaaabababbbbaabbaaabaaabaaaaaabbbbbaabaaaababbbaabb","aaabaabbabaaaaaaaaaabbb","abbbaabaabbbbbabbaababbaaaaababbaaaaabbabbbb","ababaabababbbabbbbaaabbabbbaaaaaaabbabbbaba","baababbaabbbaabbbbbbaaabbbbaaaabbbbabaabbaaabaaababbbaaabbaabaabaabaaabbbbbaabaaaaab","babbabababaabbbaabababaaaaaaaaaabbbbabbababbbaaaabbaabababbbbbbbababaaaababbaaaabaabaaabaabaaaaababbbbababbaabbaaabbabaaababbbbbabbbaaabaababbaabbabbbbaaaabababaaa","abbbbbaaaaabbaabbbabaabbabaabbbaaabbaaabaabbb","abbababb","aababaaabbbabbbbaaaabaababbababbbaaaaabbababbbbaaaaaababababaabaaaabbbabbaababbbabbabaabbababbbbabbabbbabaaabababaababbbbbaaabaabaaaabbabbaaababbabaaaaa","abbbaaaaabaabbbabbbabbaaabbaababababbbaabbababaababaabbaaababbabbb","aaabaaabaabaababbabbbbaaaaaaaaabbbabbaabbababbaabababbbbbabbabababbabaaaabbbbabbbbbbbabbabaabababbaaabbaaaaaabbababbbbbbbaabbabbaaaababbabaaabbaabaaababaabaaaabaaba","baabbabbaabbbabbbbabbbaabbabaababaaaabaaaabbaaabaaababbabbbbbabaabbbaababaaababaababbaabaabaabababaaabbbbaabbbabbbbbba","abaababaaabaabbaabaaababbaabbbababbbaaaaaabbbabaaababbaabbbbaaabaabbaaabaaaababbabbbbbababbbaabbaaababaaaaaaababbbbbba","aaaabbaaaaaabbbaaaaabbaabbaabaabbababbbbbabababbababbabbaaaaabbaaabbabbaaabbbbbbaaabbbbbabbbbbabbabbaaaaaabbbbbaaaaaabbabbbbbbabbbaabbbaababbbbbabbaaabaa","ababbaaaababababbabaaabaaaaaabbbbababaababbababaabaabababaaaabbaaabaaaaaaabbbbababbabbbbabbbbbbabbbabaabbbabbbbbabbbbbababbbbaabbbaabbbababaaaabbbbaaabbab","bbabaababbabbbbbbaabbaaaabbaaabbabbaaabbabbaabaaabbbabbbababaabbbaaba","bbaaabbbaabaababbbababaaabbbbababbbbbaabaaabbbaabbbaaaaabbaabbaabaaabbabaababaaabbaababaabbbbbbaaabbabaabababaabbbaaaaabbbaaaabaabbababaaababaabbaabaaaaabaaaababbabaabababababaabaaaabaaabbaaabbbbababa","abbaaabbbaabbabb","abbbabbaaaabaabaaababaaaaabababbbaabbbbaabbbaaa","babaaabbbbbb","baaabaaabbbabaabbbaabaabbaaaabbbabbabbbbbaabbabbbabaabababaabbbbabaabaabbaaabbbabaaaaaaaaaabbbbaaabbaaaaaabaababbaabbabaabbbabaaabbbbaabbaababba","babababbbbabbaaaaaabbbbbaba","babba","abbbabaabbabbbbbbbbababaaaaaab","bbabbabbbabaaabbbaaababbbbaaaaaaabab","bbabbaabbbabaaaaaababaabbbabaaabaaababaabaaaaaaaaaaabbaababaababbababbabbababbbaaabbaaaabbaabbbbaaabbabbbabaabbbbbabababbaabaabbbabaabaaabaaababbbabbabbaababaabbbbaabaabbabbbbabbabbaababbbbba","bbaaabaaababaaaabbaabbabbbaabbaaabaababbaaababbbaaabaabaabbabababaaaabbbbbaaaabbbbbbababbbbabbbababbaababaababbbabaaabbabaaaabababaaabababaaabbbbbaaaaababaabbbbaabaaabba","ababaaaaaabbabbabba","aaabababaabaaabaaaaabaaabaababbbbbababbbabbbbbbaabbaaaaaba","baabbbab","abbaaaaababbbaaaabbbaaabbaaababbababababaabbabaabaaabaabaaabbaaabbababbaabaaaabaabababbbbbbabaabaaabaaaababbaababbaabbbbbaabbbbbbabaa","ababaaabbababbabbbaabbbaabaaaaaaaabbabaabaaaaaabaa"}
fentoyal 发表于 2017-8-11 09:37:44 | 显示全部楼层
本帖最后由 fentoyal 于 2017-8-11 09:40 编辑

然后再给lz贴个我当时的做法。我刷的时候是抱着面试必须能写出来的思想做的(interview-friendly code),所以代码尽量简单。面试用Trie这个真心费时间(虽然我面FB时不得已也用了),所以尽量用简单好实现的做法。
我这个做法和Top voted那几个有些类似,但代码比他们短,运行速度比他们快很多(我是99%,他们在60%左右), 权当参考。
  1. class Solution {
  2.     bool isPalindrome(const string & word, int start, int end)
  3.     {
  4.         for (int i = 0; i < (end - start)/2; ++i)
  5.             if (word[start + i] != word[end - i - 1])
  6.                 return false;
  7.         return true;
  8.     }
  9. public:
  10.     vector<vector<int>> palindromePairs(vector<string>& words)
  11.     {
  12.         unordered_map<string, int> dict;
  13.         for (int i = 0; i < words.size(); ++i)
  14.             dict[words[i]] = i;
  15.         vector<vector<int>> results;
  16.         for (int i = 0; i < words.size(); ++i)
  17.         {
  18.             string temp = words[i];
  19.             reverse(temp.begin(), temp.end());
  20.             auto iter = dict.find(temp);
  21.             if (temp != words[i] && iter != dict.end())
  22.                 results.push_back(vector<int>{iter->second, i});
  23.             for (int j = 1; j <= words[i].size(); ++j)
  24.             {
  25.                 if (isPalindrome(words[i], 0, j))
  26.                 {
  27.                     string temp = words[i].substr(j, words[i].size() - j);
  28.                     reverse(temp.begin(), temp.end());
  29.                     auto iter = dict.find(temp);
  30.                     if (iter != dict.end())
  31.                         results.push_back(vector<int>{iter->second, i});
  32.                 }
  33.                 if (isPalindrome(words[i], words[i].size() - j, words[i].size()))
  34.                 {
  35.                     string temp = words[i].substr(0, words[i].size() - j);
  36.                     reverse(temp.begin(), temp.end());
  37.                     auto iter = dict.find(temp);
  38.                     if (iter != dict.end())
  39.                         results.push_back(vector<int>{i, iter->second});
  40.                 }
  41.             }
  42.         }
  43.         return results;
  44.     }
  45. };
复制代码
回复 支持 1 反对 0

使用道具 举报

fentoyal 发表于 2017-8-11 09:27:38 | 显示全部楼层
本帖最后由 fentoyal 于 2017-8-11 10:08 编辑

LZ太实诚了,我开玩笑的要了大米,LZ真的给了!!!
无功不受禄,看了LZ的求助贴,帮LZ改了下,现在可以Pass了。

LZ原来code有两处内存泄漏,我改了3 lines,分别是(改后代码里的):12,28,151。我打了感叹号的位置,应该比较醒目。原因写在inline了。lz要是不明白继续追问即可。
  1. #define CHILDSIZE 26
  2. class TrieNode{
  3. public:
  4.     TrieNode * children[CHILDSIZE];
  5.     bool isWord;
  6.     TrieNode(): isWord(false){
  7.         for (auto & child : children){
  8.             child = nullptr;
  9.         }
  10.     }

  11.     //!!!!添加TrieNode的析构,这个析构会级联(DFS)析构所有子节点。原因见下条。
  12.     ~TrieNode()
  13.     {
  14.         for (int i = 0; i < CHILDSIZE; ++i){
  15.             delete children[i];
  16.         }
  17.     }
  18. };

  19. class Trie{
  20. public:
  21.     TrieNode * root;
  22.     Trie(){
  23.         root = new TrieNode();
  24.     }
  25.     ~Trie(){
  26.         delete root; //!!!! 你原来的写法只会delete root的第一层children,可是他们也有children啊,你只杀了他们的爹而不杀他们,那这些grandchildren就变成orphan了。 所以这里delete root就好,级联DFS delete在TrieNode析构实现。
  27.     }
  28.     void insert(string word) {
  29.         TrieNode * curr = root;
  30.         for (int i = 0; i < word.size(); ++i){
  31.             //每次判断这个节点是否存在,如果不存在则创建一个
  32.             if (!curr->children[word[i]-'a']){
  33.                 curr->children[word[i]-'a'] = new TrieNode();
  34.             }
  35.             curr = curr->children[word[i]-'a'];
  36.         }
  37.         curr->isWord = true; // 全部插完后加bool标记
  38.     }

  39.     bool startsWith(string prefix) {
  40.         if (prefix.empty()){
  41.             return false;
  42.         }
  43.         TrieNode * curr = root;
  44.         for (int i = 0; i < prefix.size(); ++i){
  45.             if (curr->children[prefix[i]-'a'] == nullptr){
  46.                 return false;
  47.             }
  48.             curr = curr->children[prefix[i]-'a'];
  49.         }
  50.         //prefix每个字符都遍历完了
  51.         return true;
  52.     }
  53.     // 我们已经假设prefix是trie树的合法前缀
  54.     void findSuffix(vector<string> & res, string prefix){
  55.         TrieNode * curr = root;
  56.         for (int i = 0; i < prefix.size(); i++){
  57.             if (curr->children[prefix[i]-'a']){
  58.                 curr = curr->children[prefix[i]-'a'];
  59.             }
  60.         }
  61.         string temp = "";
  62.         for (int i = 0; i < CHILDSIZE; ++i){
  63.             if (curr->children[i]){
  64.                 TrieNode * preserved = curr;
  65.                 curr = curr->children[i];
  66.                 temp += ('a' + i);
  67.                 if (curr->isWord){
  68.                     res.push_back(prefix + temp);
  69.                 }
  70.                 findSuffix(res, prefix+temp);
  71.                 temp.pop_back();
  72.                 curr = preserved;
  73.             }
  74.         }
  75.     }
  76. };

  77. class Solution {
  78. public:
  79.     vector<vector<int>> palindromePairs(vector<string>& words) {
  80.         vector<vector<int>> res;
  81.         unordered_map<string, int > wordsMap;
  82.         if (words.empty()) return res;
  83.         bool hasEmpty = false;

  84.         // create trie
  85.         Trie * prefixTrie = new Trie();
  86.         for (int i = 0; i < words.size(); ++i){ // 正向的前缀树
  87.             prefixTrie->insert(words[i]);
  88.             wordsMap[words[i]]=i; // 构建前缀树的过程中 顺手把word:wordidx对应的map建好
  89.             if (words[i] == ""){hasEmpty = true;} // 我们认为空字符串是任何单词的前缀 也是任何单词的后缀
  90.         }
  91.         Trie * suffixTrie = new Trie();
  92.         for (string w : words){ // 反向的后缀树
  93.             reverse(w.begin(), w.end());
  94.             suffixTrie->insert(w);
  95.         }
  96.         // 查找
  97.         for (int i = 0; i < words.size(); ++i){
  98.             // 单词words[i]可能是新组合单词的前缀
  99.             if (suffixTrie->startsWith(words[i])){ //如果在后缀树里
  100.                 // 找到所有对应的单词
  101.                 vector<string> alists;
  102.                 suffixTrie->findSuffix(alists, words[i]); // 在后缀树中找到以words[i]为前缀的所有单词
  103.                 alists.push_back(words[i]); // words[i]本身也可能是后缀树的组成部分
  104.                 for (string wr : alists){
  105.                     reverse(wr.begin(), wr.end());
  106.                     string wcomb = words[i] + wr; // words[i]是新组合单词的前缀
  107.                     if (wordsMap.count(wr) && isPalindrome(wcomb)){
  108.                         int idx2 = wordsMap[wr];                     // 找对应的idx
  109.                         if (i != idx2){ //distince [i,j]
  110.                             res.push_back(vector<int>{i, idx2});
  111.                         }
  112.                     }
  113.                 }

  114.             }
  115.             // 单词words[i]可能是新组合单词的后缀
  116.             string wr = words[i];
  117.             reverse(wr.begin(), wr.end());
  118.             if (prefixTrie->startsWith(wr)){ // 如果在前缀树里
  119.                 // 找到以reverse of words[i]为前缀的所有单词
  120.                 vector<string> alists;
  121.                 prefixTrie->findSuffix(alists, wr);
  122.                 alists.push_back(wr); // words[i]本身是前缀树的一部分
  123.                 for (string w : alists){
  124.                     string wcomb = w + words[i]; // 注意这里不需要wr再reverse了! words[i]是新组合单词的前缀
  125.                     if (wordsMap.count(w) && isPalindrome(wcomb)){
  126.                         int idx2 = wordsMap[w];                     // 找对应的idx
  127.                         if (i != idx2){ //distince [i,j]
  128.                             res.push_back(vector<int>{idx2, i});
  129.                         }
  130.                     }
  131.                 }
  132.             }
  133.         }
  134.         if (hasEmpty){
  135.             int idx = wordsMap[""];
  136.             for (int i = 0; i < words.size(); ++i){
  137.                 if (i != idx && isPalindrome(words[i])){
  138.                     res.push_back(vector<int>{i,idx}); // 空字符是任何单词(如果单词本身是回文串)的后缀
  139.                     res.push_back(vector<int>{idx, i}); // 空字符是任何单词(如果单词本身是回文串)的前缀
  140.                 }
  141.             }
  142.         }
  143.         std::sort(res.begin(), res.end());
  144.         res.erase(std::unique(res.begin(), res.end()), res.end());
  145.         delete prefixTrie, suffixTrie; //!!!! C++不会自己delete pointer的,自己要手动delete。
  146.         return res;
  147.     }
  148.     // 检查单词是不是palindrome
  149.     bool isPalindrome(string &s){
  150.         if (s.empty()){return true;}
  151.         if (s.size() <= 1){ return true;}
  152.         int left = 0, right = (int)(s.size()-1);
  153.         while (left < right){
  154.             if (s[left] == s[right]){
  155.                 left++; right--;
  156.             }
  157.             else{ return false; }
  158.         }
  159.         return true;
  160.     }
  161. };

复制代码
回复 支持 1 反对 0

使用道具 举报

 楼主| 2011051305 发表于 2017-8-12 07:07:25 | 显示全部楼层
感谢前辈的指点! 闷头想了一天,也没有您指点之后领悟的快! 谢谢!
回复 支持 反对

使用道具 举报

 楼主| 2011051305 发表于 2017-8-12 07:14:54 | 显示全部楼层
fentoyal 发表于 2017-8-11 09:37
然后再给lz贴个我当时的做法。我刷的时候是抱着面试必须能写出来的思想做的(interview-friendly code),所 ...

从前辈这里学到一个非常有用的面试tip就是写题目一定要知道一种"interview-friendly code"的解法。 比如这道题用trie做,洋洋洒洒150行,很容易就有bug而且还找不到。。。
回复 支持 反对

使用道具 举报

本版积分规则

关闭

一亩三分地推荐上一条 /5 下一条

手机版|小黑屋|一亩三分地论坛声明

custom counter

GMT+8, 2017-8-24 19:02

Powered by Discuz! X3

© 2001-2013 Comsenz Inc. Design By HUXTeam

快速回复 返回顶部 返回列表