【发布时间】:2015-09-11 17:44:30
【问题描述】:
我写了下面的算法来完成一个字梯。你可以在我的 github 上找到带有 jQuery 可视化和 json 字典的完整程序:https://github.com/NateBrady23/algorithms/tree/master/word_ladder
所以我对我正在使用的算法的名称以及我正在构建的数据结构的名称知之甚少,除了我正在用每个级别的节点填充一些数组。
我从给定的输入词和结束词开始。我消除了字典中我不能使用的所有单词(输入单词和与输入单词长度不同的单词)。我构建了一个 Node 对象,它保存了它所在的跳转级别、一个值和一个 prev,这样如果我找到路径,我就可以从我的端点向后遍历。
从第 0 级开始,我的输入词,我找到所有可以通过转换一个字母从该词创建的词,并将其保存到 1 级 wordNode 的桶中。每个 Node 对象的 prev 属性都指向它所在的 0 级节点。然后我从字典中删除所有这些单词。然后,我遍历所有 1 级 wordNode,对于每一个,从修改后的字典中找到转换后的单词并将其存储在 2 级中,然后指向创建它的单词,依此类推,直到找到目标单词或没有新级别可以创建(我的话没有路径)。
因此,鉴于这个可能措辞不佳的摘要,我构建的这种类型的结构(如二叉搜索树?)以及我用来实现该结构的算法是否有名称。另外,有没有办法在不使用完全不同的结构/算法的情况下显着改进下面的代码。
<style>
span {
margin: 10px;
}
.highlight {
background-color: yellow;
font-weight: bold;
}
span {
display: inline-block;
}
</style>
<div id="path">
</div>
<script src='js/jquery.min.js'></script>
<script src='js/dictionary.js'></script>
<script>
// var dict = JSON.parse('{"aa" : true, "aah" : true, "aahed" : true}');
// Build our dictionary array
// Create a Node object so we can traverse back up the tree
function Node(value, prev, level) {
this.prev = prev;
this.level = level;
this.value = value;
}
function getRegex(word) {
var temp = [];
for(var i = 0; i < word.length; i++){
temp.push( word.substring(0,i) + '.' + word.substring(i+1) );
}
var re_str = '^(' + temp.join('|') + ')$';
return new RegExp(re_str, 'i');
}
function oneOffs(wordNode) {
var list = [];
var regex = getRegex(wordNode.value);
if ($('#' + (wordNode.level+1)).length == 0) {
$('#path').append('<div id="' + (wordNode.level+1) + '"></div>');
$('#' + (wordNode.level+1)).append('<h1>Level: ' + (wordNode.level+1));
}
for (var word in dict) {
// If we found a match
if (dict.hasOwnProperty(word) && regex.test(word)) {
list.push(new Node(word, wordNode, wordNode.level + 1));
$('#' + (wordNode.level+1)).append('<span id="' + word + '">' + word +'</span>');
delete dict[word];
}
}
return list;
}
// Get our start and end words
inputWord = 'boggle';
endWord = 'shaggy';
$('#path').append('<div id="start"><h1>Transform Case</h1><span><b>Starting Word:</b> ' + inputWord + '</span><span><b>Ending Word:</b> ' + endWord + '</span></div>');
$('#path').append('<div id="0"><h1>Level: 0</h1><span id="' + inputWord + '">' + inputWord + '</span></div>');
// Have to remove our inputWord from the dictionary
delete dict[inputWord];
// Remove all words in dictionary not of proper length
for (var word in dict) {
if (dict.hasOwnProperty(word)) {
if (word.length != inputWord.length) {
delete dict[word];
}
}
}
// Create input and end nodes
inputNode = new Node(inputWord, null, 0);
endNode = new Node(endWord, null, 0);
// Create our initial list of level 1 nodes
list = oneOffs(inputNode);
for (var node in list) {
if (list[node].value === endNode.value) {
endNode.level = list[node].level;
endNode.prev = list[node].prev;
}
}
// Build our tree
while (list.length && !endNode.level) {
newList = [];
for (var i = 0; i < list.length; i++) {
newNodeList = oneOffs(list[i]);
for (var node in newNodeList) {
if (newNodeList[node].value === endNode.value) {
endNode.level = newNodeList[node].level;
endNode.prev = newNodeList[node].prev;
break;
}
}
if (newNodeList.length) {
newList = newList.concat(newNodeList);
}
}
list = newList;
}
// if we found the path, let's traverse back up and print out all the values
if (endNode.level) {
curr = endNode;
$('#' + curr.value).addClass('highlight');
console.log(curr.value);
while(curr.prev) {
$('#' + curr.prev.value).addClass('highlight');
console.log(curr.prev.value);
curr = curr.prev;
}
} else {
console.log('No possible path');
}
</script>
【问题讨论】:
-
输入词、输出词和路径的例子是什么?似乎您正在尝试做与此类似(或相等?)的事情:stackoverflow.com/questions/1521958/…
-
是的,我就是这么做的。这是字梯问题。我只想知道我使用的算法/结构叫什么,是否可以在不改变我构建的算法/结构类型的情况下对其进行优化。
-
好吧,您使用的是与 BFS 算法类似的方法,从初始节点(您的输入词)开始,添加其所有邻居(在您的情况下为 1 个字母差异词),然后添加所有你的 1 级单词的邻居,并继续这样做,直到你找到单词或者你没有更多的节点来处理
-
如果有很多搜索,进行双面 BFS 可能会有很大帮助。
-
@Nate 可能有一些错误,但这是我使用 bfs 的实现,但都来自起始词和结束词。这样当你从双方达成一个词时,那是最短的路径。这是我的代码:jsfiddle.net/juvian/y357xudt/3,这是一个更好的解释:yucoding.blogspot.com/2013/08/…
标签: javascript algorithm