本周选题是LeetCode上面一道AC率为21%、难度为Medium的127题–Word Ladder。这道题看似是一道应用题:要求是求出从一个单词转化到目标单词的最小次数。那么它的实质是什么呢?仔细分析,从问题本质出发,不难找到相应的算法。
一、问题描述
二、问题分析
问题要求我们给出从初始单词开始,每次只能变换一个字母,最后经历最少变换次数得到最终单词并输出这个次数。注意,每次变换字母得到的新单词必须存在于给定的单词表中。初看题目,有些茫然,或许正常人都会死死盯着给定的例子,不断尝试从hit如何凑巧变道cog。但是,如果我们把这道题抽象出来,应用对应的算法,那么这道题也就迎刃而解了。注意,这其实是一个关于图的问题。每个单词可以看做一个节点,而两个单词可以经过一次变换得到就看做这两个节点间存在一条无向边。注意,所有存在于wordlist里面的单词再加上beginword构成了这个图的所有点的集合V,而边集E并没有显式的给出,需要我们自己写个函数判断两个节点间是否有边。那么,这道应用题就被抽象成“如何从一个节点经过最少的步数到达给定的节点”的问题,显然我们应该用BFS算法求解。
三、问题求解
针对问题分析,以下是c++源代码。这里,我用changeOneLetter来判断两个节点之间是否有边。
class Solution {
public:
bool changeOneLetter(string& a, string& b) {
bool dif = false;
for (int i = 0; i < a.size(); i++) {
if (a[i] != b[i]) {
if (dif == true) {
return false;
}
else {
dif = true;
}
}
}
return (dif == true) ? true : false;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
queue<string> Q;
Q.push(beginWord);
int step = 0;
while (!Q.empty()) {
int size = Q.size();
step++;
for (int i = 0; i < size; i++) {
string node = Q.front();
Q.pop();
if (node == endWord) {
return step;
}
for (auto iter = wordList.begin(); iter != wordList.end();) {
if (changeOneLetter(node, *iter)) {
Q.push(*iter);
wordList.erase(iter);
}
else {
iter++;
}
}
}
}
return 0;
}
};
可以看到,问题抽象过后,用BFS就可以很快解出了。因此遇到一个应用题,一定不要惊慌,而是要尽可能把它抽象成我们以前学过的问题,这样只需套用我们熟悉的算法即可。