Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time.
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: 5 Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5.
Example 2:
Input: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] Output: 0 Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
思路:
通过将上一题进行简单的修改就可以完成该题。当然,我们也可以通过使用D算法来简化该题。
1 上一题修改版
private:
struct TreeNode{
string val;
vector<TreeNode*> next;
TreeNode(string x) : val(x){}
};
public:
vector<TreeNode*> getNext(TreeNode* root, vector<TreeNode*> nodes){
vector<TreeNode*> nextNodes;
vector<TreeNode*> leftNodes;
for (int i = 0; i < nodes.size(); i++){
int diffCount = 0;
for (int j = 0; j < root->val.size(); j++){
if (root->val[j] != nodes[i]->val[j])
diffCount++;
}
if (diffCount == 1) nextNodes.push_back(nodes[i]);
else leftNodes.push_back(nodes[i]);
}
return nextNodes;
}
void genTree2(TreeNode *root, vector<TreeNode*> nodes){
vector<TreeNode*> record;
vector<TreeNode*> restNodes;
set<TreeNode*> usedNodes;
for (int i = 0; i < nodes.size(); i++)
if (root->val != nodes[i]->val)
usedNodes.insert(nodes[i]);
copy(usedNodes.begin(), usedNodes.end(), back_inserter(restNodes));
record.push_back(root);
TreeNode *last = root;
while (record.size() && restNodes.size()){
TreeNode *curr = record.front();
record.erase(record.begin());
vector<TreeNode*> nextNodes = getNext(curr, restNodes);
curr->next = nextNodes;
for (int i = 0; i < nextNodes.size(); i++){
if (find(record.begin(), record.end(), nextNodes[i]) == record.end())
record.push_back(nextNodes[i]);
usedNodes.erase(nextNodes[i]);
}
if (curr == last){
if (restNodes.size() == usedNodes.size()) return;
last = record.back();
restNodes = {};
copy(usedNodes.begin(), usedNodes.end(), back_inserter(restNodes));
}
}
}
void DFS2(TreeNode *root, string end, vector<string> solution, vector<vector<string>>& res, int layer, int depth){
layer++;
if (layer > depth) return;
if (!root) return;
solution.push_back(root->val);
if (root->val == end){
res.push_back(solution);
return;
}
for (int i = 0; i < root->next.size(); i++){
DFS2(root->next[i], end, solution, res, layer, depth);
}
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList){
vector<TreeNode*> nodes;
for (int i = 0; i < wordList.size(); i++){
nodes.push_back(new TreeNode(wordList[i]));
}
TreeNode *root = new TreeNode(beginWord);
genTree2(root, nodes);
vector<vector<string>> res;
DFS2(root, endWord, {}, res, 0, nodes.size());
if (res.size() == 0) return 0;
int minLen = INT_MAX;
for (int i = 0; i < res.size(); i++){
minLen = min(minLen, int(res[i].size()));
}
return minLen;
}
2 D算法版
其实我们不用完全按照D算法的规则来求解该题,因为在我们的问题中结点之间的权重是相同的。简化般的D算法如下:
int ladderLength2(string beginWord, string endWord, vector<string>& wordList){
unordered_set<string> visited;
unordered_set<string> unvisited(wordList.begin(), wordList.end());
visited.insert(beginWord);
int res = 1;
while (visited.count(endWord) == 0){
unordered_set<string> newU = unvisited;
unordered_set<string> newV = visited;
for (string v : visited){
for (string u : unvisited){
int count = 0;
for (int i = 0; i < v.size(); i++)
if (v[i] != u[i])
count++;
if (count == 1){
newV.insert(u);
newU.erase(u);
}
}
}
if (newV.size() == visited.size()) return 0;
unvisited = newU;
visited = newV;
res++;
}
return res;
}