我试图从两个给定单词之间的字典中找到最短的梯子。包括给定词和词典中的所有单词具有相同数量的字符。在一次通过中,只能更改一个字符并且需要最短路径。例如:给出:“命中”和“cil”Dic:[“hil”,“hol”,“hot”,“lot”,“lit”,“lil”]所以,答案应该是“命中” - &gt ; “HIL” - > “中CIL”
我试图用BFS解决这个问题;通过查找字典中的下一个单词并检查它是否与队列中的弹出项相邻。这种方法不会给我最短的路径:
如果,我尝试用26个字母替换每个字母,如果结果字出现在字典中,请接受:仍然这种方法不会给我最短的路径。例如:在这里,它应该给我:hit-> lit-> lot-> hot-> hol-> lil-> cil
可能更好的方法是首先构造一个树,然后在树中找到从开始单词到结束单词的最短路径。
我知道,这个论坛上有这个问题的解决方案,但没有一个解释算法。我是BFS的新手,所以不太熟悉。 我有兴趣知道如何找到最短路径之一,如果找到几条最短路径。
答案 0 :(得分:1)
我建议在字典中的单词上构建一个图表,其中一个节点代表一个单词,并且有一个来自< - >的边缘。 b如果b可以通过仅改变a中的一个字符而转换为a(当然,反之亦然)。此过程将花费O(n * n)时间,其中n为no。字典中的单词。
如何做到这一点如下:
对于每个单词构建频率字符数组,将其称为farr,这是26长度,而farr [i]告诉字符i有多少次,按字母顺序出现在单词中,然后在一个嵌套循环中运行n * n次你只需比较单词频率表的条目,它们必须只有一个字符,以便从单词a到b有一个边缘。
另请注意,此图中的边缘是无向的(在两个方向上)
在构建字典单词的完整图形后,将问题单词添加到图形中。然后继续BFS从初始字节点搜索目标字,其中所需的变换是初始字 - >目标词。
现在说你在级别'i'找到目标词,而从初始词开始探索,那么最短路径是'i'单位长。
答案 1 :(得分:0)
这种做法有点暴力,但可能是一个很好的起点。
如果目标字词等于起始字词,或者Levenshtein distance 1,则结果为[start, target]
,您就完成了。
否则你必须从起始单词中找到Levenshtein距离1的所有字典成员。如果其中一个人与目标单词的距离为1,则结果为[start, word, target]
并且您已完成。否则,您将所选列表中的每个单词作为开始并将目标作为目标递归,并将start
添加到最短结果。
伪代码 - 有点像python:
myDict = {"hil", "hol", "hot", "lot", "lit", "lil"}
used_wordlist = {}
shortestWordLadder(start, target):
if start == target or levenshtein(start, target) = 1:
return [start, target]
current_wordlist = [x for x in myDict
if x not in used_wordlist and
levenshtein(ladder[-1], x) = 1]
if current_wordlist.size = 0:
return null
for word in current_wordlist:
if levenshtein(word, target) == 1:
return [start, word, target]
used_wordlist.insert_all(current_wordlist)
min_ladder_size = MAX_INT
min_ladder = null
for word in currrent_wordlist:
ladder = shortestWordLadder(word, target)
if ladder is not null and ladder.size < min_ladder_size:
min_ladder_size = ladder.size
min_ladder = ladder.prepend(start)
return min_ladder
可能的优化:
我考虑重复使用levenshtein(start, target)
内部创建的矩阵,但我无法获得足够的信心,它会在所有情况下都有效。我们的想法是从矩阵的右下角开始,选择最小的邻居,从字典中创建一个单词。然后继续这个位置。如果当前单元格的邻居没有从字典中创建单词,我们必须回溯,直到找到通向值为0的字段的方法。如果回溯将我们带回到右下方的单元格,则没有解决方案。
我现在不确定,可能没有解决方案,你可能会忽略这种方式。如果它找到了解决方案,我非常有信心,它是最短的解决方案之一。
目前我没有时间思考它。如果证明这不是一个完整的解决方案,您可以将其用作优化步骤而不是levenshtein(start, target)
第一行中的shortestWOrdLadder()
调用,因为算法会为您提供Levenshtein距离,如果可能的话,最短的路径。
答案 2 :(得分:0)
我采用以下方法制定了解决方案: 1.)我先从字典中建了一棵树,假设起点是给定的单词;并查找与该单词相邻的所有单词,依此类推 2.)接下来,我尝试使用这个树构建从给定单词到结束单词的所有可能路径。
复杂度:O(n * 70 + 2 ^ n-1 * lg(n))= O(2 ^ n-1 * lg(n))这里n是字典中的单词数,70出来作为从65到122(A到a)的ASCII值范围,我在这里采取了一个圆形的数字。如预期的那样,复杂性是指数级的。 即使经过一定的优化,最坏情况的复杂性也不会发生变化。
这是我写的代码(由我测试并且有效。任何错误或建议都会受到高度赞赏。):
#include <iostream>
#include <vector>
#include <cstring>
#include <deque>
#include <stack>
#include <algorithm>
using namespace std;
struct node {
string str;
vector<node *> children;
node(string s) {
str = s;
children.clear();
}
};
bool isAdjacent(string s1, string s2) {
int table1[70], table2 [70];
int ct = 0;
for (int i = 0; i < 70; i++) {
table1[i] = 0;
table2[i] = 0;
}
for (int i = 0; i < s1.length(); i++) {
table1[((int)s1[i])- 65] += 1;
table2[((int)s2[i])- 65] += 1;
}
for (int i = 0; i < 70; i++) {
if (table1[i] != table2[i])
ct++;
if (ct > 2)
return false;
}
if (ct == 2)
return true;
else
return false;
}
void construct_tree(node *root, vector<string> dict) {
deque<node *> q;
q.push_back(root);
while (!q.empty()) {
node *curr = q.front();
q.pop_front();
if (dict.size() == 0)
return;
for (int i = 0; i < dict.size(); i++) {
if (isAdjacent(dict[i], curr->str)) {
string n = dict[i];
dict.erase(dict.begin()+i);
i--;
node *nnode = new node(n);
q.push_back(nnode);
curr->children.push_back(nnode);
}
}
}
}
void construct_ladders(stack<node *> st, string e, vector<vector <string> > &ladders) {
node *top = st.top();
if (isAdjacent(top->str,e)) {
stack<node *> t = st;
vector<string> n;
while (!t.empty()) {
n.push_back(t.top()->str);
t.pop();
}
ladders.push_back(n);
}
for (int i = 0; i < top->children.size(); i++) {
st.push(top->children[i]);
construct_ladders(st,e,ladders);
st.pop();
}
}
void print(string s, string e, vector<vector<string> > ladders) {
for (int i = 0; i < ladders.size(); i++) {
for (int j = ladders[i].size()-1; j >= 0; j--) {
cout<<ladders[i][j]<<" ";
}
cout<<e<<endl;
}
}
int main() {
vector<string> dict;
string s = "hit";
string e = "cog";
dict.push_back("hot");
dict.push_back("dot");
dict.push_back("dog");
dict.push_back("lot");
dict.push_back("log");
node *root = new node(s);
stack<node *> st;
st.push(root);
construct_tree(root, dict);
vector<vector<string> > ladders;
construct_ladders(st, e, ladders);
print(s,e,ladders);
return 0;
}