vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict){ dict.emplace(start); dict.emplace(end); unordered_map<string, vector<string>> from; queue<string> que; que.push(start); dict.erase(start); int endLevel = -1; int level = 0; while(!que.empty()){ if(endLevel != -1) break; int size = que.size(); unordered_set<string> toPush;//this is acctually what the next level is for(int ttt = 0; ttt < size; ttt++){ string front = que.front(); if(front == end){ endLevel = level; break; } for(unsigned int i = 0; i < front.size(); i++){ string neighbor = front; for(int j = 0; j < 26; j++){ neighbor[i] = (char)((int)'a' + j); if(neighbor == front) continue; if((dict.count(neighbor) != 0)){ from[neighbor].push_back(front); toPush.emplace(neighbor); } } } que.pop(); } level++; for(unordered_set<string>::iterator itr = toPush.begin(); itr != toPush.end(); itr++){ string temp = *itr; que.push(temp); dict.erase(temp); //every time after next level is determined, erase them from dict //since they won't be at the next next level(we need to exclude them from the future check) } } vector<vector<string>> result; if(from[end].size() == 0) return result; vector<string> tempRes; tempRes.push_back(end); help(result, tempRes, endLevel, start, end, from); return result; }
shared_ptr<HashTables::BNode> HashTables::buildCannonicTree_helper(shared_ptr<BSTNode<int> > &n, unordered_set<shared_ptr<BNode>, HashBNode, EqualBNode> &table) { if (!n) return nullptr; shared_ptr<BNode> left = buildCannonicTree_helper(n->left, table); shared_ptr<BNode> right = buildCannonicTree_helper(n->right, table); shared_ptr<BNode> newNode(new BNode(n->data, left, right)); table.emplace(newNode); return newNode; }
void reverseDFS(size_t idx) { if (visit[idx]) return; visit[idx] = true; for (auto next : revGraph[idx]) { reverseDFS(next); } selectedWord.emplace(sccId[idx]); sum++; }
void addClockReceiver(shared_ptr<Clocked> receiver) { clock_receivers.emplace(receiver); }
/** * @param start, a string * @param end, a string * @param dict, a set of string * @return a list of lists of string */ vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) { vector<vector<string>> ans; /* in the pair, the vector contains all immediate and legal children of the node, int is the order of the node */ unordered_map<string, std::pair<vector<string>, int>> g; /* Put end on the dict to make sure we have an ending point on the graph */ dict.emplace(end); size_t len = start.length(); char old_char = 0; string str, key; queue<string> q; q.push(start); while (false == q.empty()) { key = std::move(q.front()); q.pop(); if (key == end) break; str = key; /* Since we use a huge structure to store graph info, g[key] should be created already when we set up its order during BFS. This is only for the string start as the key. BTW, for an existing key-value in unordered_map, try to emplace again will simply be ignored. In other words, newly given value will NOT replace the existing one. */ if (start == key) g.emplace(key, std::make_pair(vector<string>(), 0)); for (size_t i = 0; i < len; ++i) { for (char j = 'a'; j <= 'z'; ++j) { if (j == str[i])continue; old_char = str[i]; str[i] = j; if (dict.end() != dict.find(str)) { /* We will only process for the following two conditions: 1. Node str has not been visited yet during a BFS. This can be confirmed by g.find(str) == g.end(); 2. Node str has been visited. However, the current key's order is one level above node str. In other words, according to the transform rule and common sense of a "shortest path", node key to node str is legit and str should be considered as key's legal child even though str has other parent(s). */ if (g.end() == g.find(str) || g[str].second == g[key].second + 1) { /* If g.find on str returns end, it means node str has not been visited yet */ if (g.end() == g.find(str)) { /* we should only push str to the queue if str hasn't be on the queue before. otherwise, we will introduce duplications onto the neighor list of str. */ q.push(str); g.emplace(str, std::make_pair(vector<string>(), g[key].second + 1)); } /* however, we will put str onto key's neighor list even str is accessed before for an obvious reason: we need to find all possible routes even they may overlap in between (not completely though). In such scenario, str has multiple parents. */ g[key].first.push_back(str); } } str[i] = old_char; } } } vector<string> vec(dict.size() + 2); this->aux(ans, vec, g, start, end, 0); return ans; }
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict){ dict.emplace(start); dict.emplace(end); unordered_map<string, vector<string>> from; queue<string> que; que.push(start); dict.erase(start); int endLevel = -1; int level = 0; while(!que.empty()){ if(endLevel != -1) break; int size = que.size(); unordered_set<string> toPush;//this is acctually what the next level is for(int ttt = 0; ttt < size; ttt++){ string front = que.front(); if(front == end){ endLevel = level; break; } for(unsigned int i = 0; i < front.size(); i++){ string neighbor = front; for(int j = 0; j < 26; j++){ neighbor[i] = (char)((int)'a' + j); if(neighbor == front) continue; if((dict.count(neighbor) != 0)){ from[neighbor].push_back(front); //very important trick here: keep track of where the neighbor //is from. This will improve the backtrack process since all //the string we trace back from end will lead us back to nothing but start, //we can avoid a lot of unnecessary check here toPush.emplace(neighbor); } } } que.pop(); } /* * Here is what I don't understand. I firstly use following codes to find neighbors the current string, "front", * can "jump" to, by iterating the whole dict. I thought this should be faster than iterating chars in * the current string since the iterating the whole dict will take O(dict.size() * each level's size * length of string) * while above code takes O(26^length fo string) in time, which should be much greater than the first one. * However, I failed with the following case. Can anyone explain the reason, please? string front = que.front(); dict.erase(front); if(front == end){ endLevel = level; break; } else{ for(unordered_set<string>::iterator itr = dict.begin(); itr != dict.end(); itr++){ string neighbor = *itr; if(help2(neighbor, front)){ from[neighbor].push_back(front); toPush.emplace(neighbor); } } } que.pop(); } */ level++; for(unordered_set<string>::iterator itr = toPush.begin(); itr != toPush.end(); itr++){ string temp = *itr; que.push(temp); dict.erase(temp); //every time after next level is determined, erase them from dict //since they won't be at the next next level(we need to exclude them from the future check) } } vector<vector<string>> result; if(from[end].size() == 0) return result; vector<string> tempRes; tempRes.push_back(end); help(result, tempRes, endLevel, start, end, from); return result; }