单词接龙
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk:
- 每一对相邻的单词只差一个字母。
- 对于
1 <= i <= k时,每个si都在wordList中。注意,beginWord不需要在wordList中。 sk == endWord
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。
示例 1:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
示例 2:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
输出:0
解释:endWord "cog" 不在字典中,所以无法进行转换。
提示:
1 <= beginWord.length <= 10endWord.length == beginWord.length1 <= wordList.length <= 5000wordList[i].length == beginWord.lengthbeginWord、endWord和wordList[i]由小写英文字母组成beginWord != endWordwordList中的所有字符串 互不相同
解题
一句话题解
- 无向图中(一次转换相当于一个边)两个顶点之间的最短路径的长度,可以通过广度优先遍历得到;
BFS 广度优先搜索 (2000 ms):
var ladderLength = function (beginWord, endWord, wordList) {
if (wordList.indexOf(endWord) === -1) return 0
var checkWord = function (begin, end) {
let diff = 0
for (let i = 0; i < begin.length; i++) {
if (begin[i] !== end[i]) {
diff += 1
if (diff > 1) {
return diff
}
}
}
return diff
}
let visited = {}
wordList.forEach(item => {
visited[item] = false
})
var bfs = function (arr, depth) {
if (arr.indexOf(endWord) > -1) return depth
let li = []
arr.forEach(item => {
for (let k in visited) {
if (checkWord(k, item) === 1) {
li.push(k)
delete visited[k]
}
}
})
if (li.length === 0) {
return 0
}
return bfs(li, depth + 1)
}
let res = bfs([beginWord], 1)
return res
}
优化visted标记(400ms)
第一版耗时太长,做了一点优化,把 visited 从 Hash 改成 boolean 数组,通过 index 判断是否已访问。这样判断 visited 只需要 boolean 数组判断,节省了大量 Hash 操作。耗时下降为 400 ms。
var ladderLength = function (beginWord, endWord, wordList) {
if (wordList.indexOf(endWord) === -1) return 0
var checkWord = function (begin, end) {
let diff = 0
for (let i = 0; i < begin.length; i++) {
if (begin[i] !== end[i]) {
diff += 1
if (diff > 1) {
return diff
}
}
}
return diff
}
let visted = Array(wordList.length).fill(false)
let bfs = function (list, depth) {
let len = list.length
let li = []
while (len-- > 0) {
let cur = list.shift()
for (let i = 0; i < wordList.length; i++) {
let s = wordList[i]
if (visted[i] || checkWord(s, cur) !== 1) continue
if (s === endWord) return depth + 2
visted[i] = true
li.push(s)
}
}
if (li.length === 0) return 0
return bfs(li, depth + 1)
}
return bfs([beginWord], 0)
}