赞
踩
将一个单词列表使用words组装起来,实现如下:(仅含有小写的字典),可以在log(m)时间内查询一个单词是否在字典中。
class Trie { public: vector<Trie *>curLevel; bool isEnd = false; Trie() : curLevel(26) { } void insert(string word) { Trie * curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } // check nextLevel curNode = curNode->curLevel[c]; } curNode->isEnd = true; } bool search(string word) { Trie * curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return curNode->isEnd; } bool startsWith(string prefix) { Trie * curNode = this; for(char c : prefix) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return true; } };
https://leetcode-cn.com/problems/word-search-ii
class Solution { public: class Trie { public: vector<Trie*> curLevel; bool isEnd = false; bool hasNext = true; Trie() : curLevel(26) { } void insert(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; curNode->hasNext = true; } curNode->isEnd = true; } bool inTrie(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return curNode->isEnd; } bool startWith(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return true; } bool endWith(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return !curNode->hasNext; } }; vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { int m = board.size(); int n = board[0].size(); // build trie in normal or reverse order // std::shared_ptr<Trie> treeNormal = make_shared<Trie>(); Trie* treeNormal = new Trie(); // std::unique_ptr<Trie> treeReverse = new Trie(); for(auto w : words) { treeNormal->insert(w); // treeReverse.insert(reverse(w.begin(), w.end())); } int deltaX[] = {1, 0, -1, 0}; int deltaY[] = {0, 1, 0, -1}; // get the answer vector<string> res; unordered_set<string> hash; for(int i = 0; i < board.size(); ++i) { for(int j = 0; j < board[0].size(); ++j) { // std::cout << "check next st point!" << endl; string tmpRes = ""; vector<vector<bool>> exploredFlag(m, vector<bool>(n, false)); backTrack(i, j, board, tmpRes, res, treeNormal, deltaX, deltaY, exploredFlag, hash ); } } return res; } /** [["o","a","a","n"], ["e","t","a","e"], ["i","h","k","r"], ["i","f","l","v"]] ["oath","pea","eat","rain","oathi","oathk","oathf","oate","oathii","oathfi","oathfii"] **/ void backTrack(int i, int j, vector<vector<char>>& board, string& tmpRes, vector<string>& res, Trie* curNode, const int* deltaX, const int* deltaY, vector<vector<bool>>& exploredFlag, unordered_set<string>& hash) { char ch = board[i][j]; if(nullptr == curNode->curLevel[ch - 'a']) { return ; } // start from i, j tmpRes.push_back(board[i][j]); // Trie* lastNode = curNode; curNode = curNode->curLevel[ch - 'a']; if(nullptr == curNode) { cout << "a???" << endl; return ; } // cout << "start : in " << i << "->" << j << " " << board[i][j] << "with tmpRes : " << tmpRes << endl; // we check the tmpRes directly using the trie // if(tree->inTrie(tmpRes) && 0 == hash.count(tmpRes)) { // res.emplace_back(tmpRes); // hash.insert(tmpRes); // if(tree->endWith(tmpRes)) { // tmpRes.pop_back(); // return; // } // } if(nullptr != curNode && curNode->isEnd == true && 0 == hash.count(tmpRes)) { // cout << "find! >>>>> " << tmpRes << endl; res.emplace_back(tmpRes); hash.insert(tmpRes); if(!curNode->hasNext) { tmpRes.pop_back(); return; } } // cout << "current[i, j] : in " << i << "->" << j << " " << board[i][j] << "with tmpRes : " << tmpRes << endl; exploredFlag[i][j] = true; if(nullptr != curNode) { // not null for(int mvIdx = 0; mvIdx < 4; ++mvIdx) { int nextX = i + deltaX[mvIdx]; int nextY = j + deltaY[mvIdx]; // cout << "tryStart: [x, y] :" << nextX << " " << nextY << endl;; if( nextX < board.size() && nextX >= 0 && nextY < board[0].size() && nextY >= 0 && \ ! exploredFlag[nextX][nextY]) { backTrack(nextX, nextY, board, tmpRes, res, curNode, deltaX, deltaY, exploredFlag, hash ); } // cout << "tryFinish: [x, y] :" << nextX << " " << nextY << endl;; } } exploredFlag[i][j] = false; tmpRes.pop_back(); } // OLD WAY TO DO, will exceed the time limitation // void backTrack(int i, int j, vector<vector<char>>& board, string& tmpRes, vector<string>& res, unique_ptr<Trie>& tree, // const int* deltaX, const int* deltaY, // vector<vector<bool>>& exploredFlag, // unordered_set<string>& hash) { // // start from i, j // tmpRes.push_back(board[i][j]); // // cout << "start : in " << i << "->" << j << " " << board[i][j] << "with tmpRes : " << tmpRes << endl; // if(tree->inTrie(tmpRes) && 0 == hash.count(tmpRes)) { // res.emplace_back(tmpRes); // hash.insert(tmpRes); // if(tree->endWith(tmpRes)) { // tmpRes.pop_back(); // return; // } // } // // cout << "current[i, j] : in " << i << "->" << j << " " << board[i][j] << "with tmpRes : " << tmpRes << endl; // exploredFlag[i][j] = true; // if(tree->startWith(tmpRes)) { // for(int mvIdx = 0; mvIdx < 4; ++mvIdx) { // int nextX = i + deltaX[mvIdx]; // int nextY = j + deltaY[mvIdx]; // if( nextX < board.size() && \ // nextX >= 0 && \ // nextY < board[0].size() && \ // nextY >= 0 && \ // ! exploredFlag[nextX][nextY]) { // backTrack(nextX, nextY, board, tmpRes, res, tree, // deltaX, deltaY, exploredFlag, hash // ); // } // // cout << "tryFinish: [x, y] :" << nextX << " " << nextY << endl;; // } // } // exploredFlag[i][j] = false; // tmpRes.pop_back(); // // cout << "current[i, j] : exit " << i << "->" << j << " " << board[i][j] << "with tmpRes : " << tmpRes << endl; // } };
https://leetcode-cn.com/problems/palindrome-pairs/
class Solution { public: class Trie { public: vector<Trie*> curLevel; bool isEnd = false; int wordIdx = -1; Trie() : curLevel(26), wordIdx(-1) { } void insert(string& word, int idx) { Trie* curNode = this; for(auto c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; } curNode->isEnd = true; curNode->wordIdx = idx; } int inTrie(string word) { Trie* curNode = this; for(auto c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return -1; } curNode = curNode->curLevel[c]; } return curNode->wordIdx; } int inTrie(string& word, int left, int right) { Trie* curNode = this; for(int i = right; i >= left; --i) { char c = word[i] - 'a'; if(nullptr == curNode->curLevel[c]) { return -1; } curNode = curNode->curLevel[c]; } return curNode->wordIdx; } }; vector<vector<int>> palindromePairs(vector<string>& words) { // travel all prefix and subfix of a word, // find the palindrome and check the existence in the words of // reverse of the other part Trie* tree = new Trie(); // Trie* treeReverse = new Trie(); unordered_map<string, int> strToIdx; // int idx = 0; // for(auto word : words) { // tree->insert(word); // strToIdx[word] = idx++; // } // int ans = 0; // vector<vector<int>> res = {}; // for(auto word : words) { // deque<string> prefix; // deque<string> subfix; // int n = word.size(); // for(int st = 0; st <= n; ++st) { // string pre = word.substr(0, st); // string sub = word.substr(st); // // cout << "p/s : " << pre << " / " << sub << endl; // if(checkPalindrome(pre)) { // reverse(sub.begin(), sub.end()); // if(tree->inTrie(sub)) { // vector<int> resItem = {strToIdx[sub], strToIdx[word]}; // if(resItem[1] != resItem[0]) { // // cout << "push: " << word + sub << endl; // res.emplace_back(resItem); // } // } // } // if(checkPalindrome(sub) && pre.size() != n) { // reverse(pre.begin(), pre.end()); // if(tree->inTrie(pre)) { // vector<int> resItem = {strToIdx[word], strToIdx[pre]}; // if(resItem[1] != resItem[0]) { // // cout << "push: " << pre + word << endl; // res.emplace_back(vector<int>(resItem)); // } // } // } // } // } int idx = 0; for(auto word : words) { // tree->insert(word, idx); // reverse(word.begin(), word.end()); tree->insert(word, idx); ++idx; } int tmp = 0; int ans = 0; vector<vector<int>> res = {}; int curWordIdx = 0; for(auto word : words) { int n = word.size(); for(int st = 0; st <= n; ++st) { string pre = word.substr(0, st); string sub = word.substr(st); // cout << "p/s : " << pre << " / " << sub << " curWordIdx : " << curWordIdx << endl; // if(checkPalindrome(pre)) { if(0 != st && checkPalindrome(word, 0, st-1)) { // reverse(sub.begin(), sub.end()); int subIdx = tree->inTrie(word, st, n-1); // cout << "subIdx = " << sub << "with idx = " << subIdx << endl; if(subIdx != -1 && curWordIdx != subIdx) { // cout << "curWordIdx / subIdx" << curWordIdx << "/" << subIdx << endl; // cout << "push: " << sub << "+" << word << endl; res.emplace_back(vector<int>({subIdx, curWordIdx})); } } if(checkPalindrome(word, st, n-1)) { // reverse(pre.begin(), pre.end()); int preIdx = tree->inTrie(word, 0, st-1); if(preIdx != -1 && preIdx != curWordIdx) { // cout << "curWordIdx / preIdx" << curWordIdx << "/" << preIdx << endl; // cout << "push: " << pre << "+" + word << endl; res.emplace_back(vector<int>({curWordIdx, preIdx})); } } } ++curWordIdx; } return res; } // for (int i = 0; i < n; i++) { // int m = words[i].size(); // for (int j = 0; j <= m; j++) { // if (isPalindrome(words[i], j, m - 1)) { // int left_id = findWord(words[i], 0, j - 1); // if (left_id != -1 && left_id != i) { // ret.push_back({i, left_id}); // } // } // if (j && isPalindrome(words[i], 0, j - 1)) { // int right_id = findWord(words[i], j, m - 1); // if (right_id != -1 && right_id != i) { // ret.push_back({right_id, i}); // } // } // } // } bool checkPalindrome(string& s, int left, int right) { int len = right - left + 1; for(int i = 0; i < len / 2; ++i) { if(s[left + i] != s[right - i]) { return false; } } return true; } // bool checkPalindrome(string& s) { // int n = s.size(); // for(int i = 0; i < n / 2; ++i) { // if(s[i] != s[n - i - 1]) { // return false; // } // } // return true; // } };
class Solution { public: class Trie { public: vector<Trie*> curLevel; bool isEnd = false; int wordIdx = -1; Trie() : curLevel(26), wordIdx(-1) { } void insert(string& word, int idx) { Trie* curNode = this; for(auto c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; } curNode->isEnd = true; curNode->wordIdx = idx; } int inTrie(string word) { Trie* curNode = this; for(auto c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return -1; } curNode = curNode->curLevel[c]; } return curNode->wordIdx; } int inTrie(string& word, int left, int right) { Trie* curNode = this; for(int i = right; i >= left; --i) { char c = word[i] - 'a'; if(nullptr == curNode->curLevel[c]) { return -1; } curNode = curNode->curLevel[c]; } return curNode->wordIdx; } }; vector<string> wordReverse; unordered_map<string, int> strToIdx; int findWord(string& s, int left, int right) { string tmp = s.substr(left, right - left + 1); auto it = strToIdx.find(tmp); int res = it == strToIdx.end() ? -1 : it->second; // cout << "finding: " << tmp << " with ans = " << res << endl; return res; } vector<vector<int>> palindromePairs(vector<string>& words) { // travel all prefix and subfix of a word, // find the palindrome and check the existence in the words of // reverse of the other part int idx = 0; for(auto word : words) { reverse(word.begin(), word.end()); wordReverse.emplace_back(word); strToIdx[word] = idx; ++idx; } vector<vector<int>> res = {}; int curWordIdx = 0; for(auto word : words) { int n = word.size(); for(int st = 0; st <= n; ++st) { // cout << "p/s : " << " / " << " curWordIdx : " << curWordIdx << endl; if(0 != st && checkPalindrome(word, 0, st-1)) { int subIdx = findWord(word, st, n-1); // cout << "subIdx = " << subIdx << endl; if(subIdx != -1 && curWordIdx != subIdx) { res.emplace_back(vector<int>({subIdx, curWordIdx})); } } if(checkPalindrome(word, st, n-1)) { int preIdx = findWord(word, 0, st-1); if(preIdx != -1 && preIdx != curWordIdx) { res.emplace_back(vector<int>({curWordIdx, preIdx})); } } } ++curWordIdx; } return res; } bool checkPalindrome(string& s, int left, int right) { int len = right - left + 1; for(int i = 0; i < len / 2; ++i) { if(s[left + i] != s[right - i]) { return false; } } return true; } };
https://leetcode-cn.com/problems/word-break-ii/
class Solution { public: class Trie { public: vector<Trie*> curLevel; bool isEnd = false; Trie() : curLevel(26){} void insert(string word ) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; } curNode->isEnd = true; } bool inTrie(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return curNode->isEnd; } bool startWith(string word) { Trie* curNode = this; for(char c : word) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { return false; } curNode = curNode->curLevel[c]; } return true; } }; vector<string> wordBreak(string s, vector<string>& wordDict) { // implement a trie to sort the word Dict Trie* tree = new Solution::Trie(); for(string s : wordDict) { tree->insert(s); } vector<string> tmpRes; vector<vector<string>> res; backTrack(s, tmpRes, res, tree); vector<string> finalRes; for(auto& strVec : res) { string resItem = ""; for(auto& str : strVec) { resItem += (str + " "); } finalRes.emplace_back(resItem.substr(0, resItem.size() - 1)); } return finalRes; } void backTrack(string s, vector<string> tmpRes, vector<vector<string>>& res, Trie* trie) { if(0 == s.size()) { res.emplace_back(tmpRes); } // try every possibility for(int i = 0; i < s.size(); ++i) { string headWord = s.substr(0, i + 1); tmpRes.emplace_back(headWord); // cout << "head -> " << headWord << endl; if(trie->inTrie(headWord)) { // cout << "in it!" << endl; backTrack(s.substr(i + 1), tmpRes, res, trie); } tmpRes.pop_back(); } } };
https://leetcode-cn.com/problems/concatenated-words/
when checking : aaaakaa the sufix start from pos : 4 has been validated to be failure!
when checking : aaaakaa the sufix start from pos : 3 has been validated to be failure!
when checking : aaaakaa the sufix start from pos : 2 has been validated to be failure!
when checking : aaaakaa the sufix start from pos : 4 has been validated to be failure!
class Solution { public: class Trie{ public: vector<Trie*> curLevel; bool isEnd = false; // bool hasNext = false; Trie() : curLevel(26) { } void insert(string& s, int idx) { // cout << "inserting : " << s << endl; Trie* curNode = this; for(auto c : s) { c -= 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; // curNode->hasNext = true; } curNode->isEnd = true; } }; vector<string> findAllConcatenatedWordsInADict(vector<string>& words) { int n = words.size(); Trie* tree = new Trie(); // build trie int idx = 0; sort(words.begin(), words.end(), [](string& a, string& b){ return a.size() < b.size(); }); vector<string> ans; for(auto w : words) { // cout << "-------checking " << w << endl; // bool ableToConnect = false; // findMaxConnectedCnt(w, 0, tree, 0, ableToConnect); // if(ableToConnect ) { // ans.emplace_back(w); // } vector<bool> trap(w.size(), false); if(dfsToCheck(w, 0, tree, 0, trap)) { ans.emplace_back(w); } tree->insert(words[idx], idx); ++idx; } return ans; } // here we search all the possible ways, but we only need one possible way, so we need return early void findMaxConnectedCnt(string& s, int pos, Trie* root, int curCnt, bool& ableToConnect) { if(s.size() == pos) { if(curCnt >= 2) { ableToConnect = true; } // cout << "<<<<<< finish one!" << endl; return ; } int curPos = pos; Trie* curNode = root; while(curPos < s.size()) { // serach all prefix int ch = s[curPos] - 'a'; if(nullptr != curNode->curLevel[ch]) { if(curNode->curLevel[ch]->isEnd) { // cout << ">>>>> curPos: " << curPos << " char is " << s[curPos] << " dive with curCnt: " << curCnt << endl; // using this or next end findMaxConnectedCnt(s, curPos + 1, root, curCnt + 1, ableToConnect); } } else { return; } // cout << "curPos: " << curPos << " char is " << s[curPos] << " with curCnt: " << curCnt << endl; curNode = curNode->curLevel[ch]; ++curPos; } } bool dfsToCheck(string& s, int pos, Trie* root, int curCnt, vector<bool>& trap) { if(s.size() == pos) { return curCnt >= 2; } if(trap[pos]) { cout << "when checking : " << s << " the sufix start from pos : " << pos << " has been validated to be failure!" << endl; return false; } int curPos = pos; Trie* curNode = root; while(curPos < s.size()) { // serach all prefix int ch = s[curPos] - 'a'; if(nullptr != curNode) { if(nullptr != curNode->curLevel[ch]) { if(curNode->curLevel[ch]->isEnd) { // cout << ">>>>> curPos: " << curPos << " char is " << s[curPos] << " dive with curCnt: " << curCnt << endl; // using this or next end if(dfsToCheck(s, curPos + 1, root, curCnt + 1, trap)) { return true; } } } } else { break; } // cout << "curPos: " << curPos << " char is " << s[curPos] << " with curCnt: " << curCnt << endl; curNode = curNode->curLevel[ch]; ++curPos; } trap[pos] = true; return false; } };
https://leetcode-cn.com/problems/prefix-and-suffix-search/
For a word like “test”, consider “#test”, “t#test”, “st#test”, “est#test”, “test#test”. Then if we have a query like prefix = “te”, suffix = “t”, we can find it by searching for something we’ve inserted starting with “t#te”.
class WordFilter { public: // containning suffix class Trie { public: vector<Trie*> curLevel; int idx = -1; Trie() : curLevel(27) {} void insert(string& word, int idx, int left, int right) { Trie* curNode = this; for(int i = left; i < right; ++i) { char c = word[i]; c = (c == '#' ? 26 : c - 'a'); if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; curNode->idx = idx; } curNode->idx = idx; } int startWith(string& word) { Trie* curNode = this; int lastIdx = -1; for(auto c : word) { // cout << "checking char: " << c << endl; c = (c == '#' ? 26 : c - 'a'); if(nullptr == curNode->curLevel[c]) { return -1; } curNode = curNode->curLevel[c]; } return curNode->idx; } }; public: Trie* tree; WordFilter(vector<string>& words) { tree = new Trie(); for(int wIdx = 0; wIdx < words.size(); ++wIdx) { int n = words[wIdx].size(); string word = words[wIdx] + "#" + words[wIdx]; for(int j = 0; j <= n - 1; ++j) { // string tmp = word.substr(j); // overwrite those who start with a same suffix and prefix // cout <<"insert : " << tmp << endl; tree->insert(word, wIdx, j, 2*n +1); } } } int f(string prefix, string suffix) { int ans = -1; string tmp = suffix + "#" + prefix; // cout << "target >> " << tmp << endl; return tree->startWith(tmp); } };
https://leetcode-cn.com/problems/stream-of-characters/
class StreamChecker { public: class Trie{ public: vector<Trie*> curLevel; bool isEnd = false; Trie() : curLevel(26) {} void insert(string& word) { Trie* curNode = this; int n = word.size(); for(int i = n-1; i >= 0; --i) { char c = word[i] - 'a'; if(nullptr == curNode->curLevel[c]) { curNode->curLevel[c] = new Trie(); } curNode = curNode->curLevel[c]; } curNode->isEnd = true; } bool inTrie(string& word) { Trie* curNode = this; int n = word.size(); for(int i = n-1; i >= 0; --i) { char c = word[i] - 'a'; if(nullptr == curNode->curLevel[c]) { return false; } if(curNode->curLevel[c]->isEnd) { return true; } curNode = curNode->curLevel[c]; } return curNode->isEnd; } }; Trie* root; string curStr; StreamChecker(vector<string>& words) { root = new Trie(); for(auto& w : words) { root->insert(w); } curStr = ""; } bool query(char letter) { curStr += letter; return root->inTrie(curStr); } }; /** * Your StreamChecker object will be instantiated and called as such: * StreamChecker* obj = new StreamChecker(words); * bool param_1 = obj->query(letter); *
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。