127. Word Ladder
一开始当字符暴力搜索,TLE。
设置了提前停止的情况,依然TLE。
后来看答案是BFS,才明白怎么回事。
找转移过程中的最短途径,其实可以当做是最短路径来做。
然后问题就是怎么建立图。
想法是,到一个点,看看WORDLIST里哪个单词从现在转移,然后加入QUEUE建立搜索过程。
CODEGANKER提供的方法是,不查WORDLIST,而是把当前单词的每个字母都用a-z替换,替换之后存在于WORDLIST就加到QUEUE里,最多就25*word.length的可能性。
剩下的就是需要记住每一层加入了多少个单词,检验完进入下一层LEVEL+1。
(http://blog.csdn.net/linhuanmars/article/details/23029973)
重点是BFS的抽象。。
public int ladderLength(String beginWord, String endWord, Set<String> wordList)
{
Queue<String> que = new LinkedList<String>();
Set<String> visited = new HashSet<String>();
que.add(beginWord);
visited.add(beginWord);
int seen = 1;
int level = 1;
int toSee = 0;
while(!que.isEmpty())
{
String tempString = que.poll();
seen--;
for(int n = 0; n < tempString.length();n++)
{
char[] tempChArr = tempString.toCharArray();
for(char m = 'a'; m <= 'z'; m++)
{
tempChArr[n] = m;
String curString = new String(tempChArr);
if(curString.equals(endWord)) return level+1;
if(wordList.contains(curString) && !visited.contains(curString))
{
que.add(curString);
visited.add(curString);
toSee++;
}
}
}
if(seen == 0)
{
seen = toSee;
toSee = 0;
level++;
}
}
return 0;
}
另一个需要想明白的是,深度搜索在每次迭代后,都要让变量变回原来的样子,比如VISITED如果是深度搜索,需要remove last word,以保证下次下次搜索可以使用当前单词。
而广度搜索则不用remove,因为下次不可能使用当前的单词,只能往深搜索。
二刷。
这个题还有印象。
其实是个图像题,每个Sring是个vertex,有edge到另一个vertex说明可以转化,当然要自己构建。
构建之后做一个BFS找最短路径。
BFS就一个套路,问题就在于如何判断俩单词是否可以转化。
一刷的时候我记得是看了code ganker的一个巧妙的方法。这次尝试用自己的办法,String A, String B,遍历比较不同,等于1就TRUE,否则FALSE.
结果TLE...靠,做了好久的。。

public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList)
{
Queue<String> q = new LinkedList<String>();
Set<String> check = new HashSet<String>();
q.add(beginWord);
check.add(beginWord);
int cur = 1;
int level = 1;
int total = 0;
while(!q.isEmpty())
{
String temp = q.poll();
cur--;
String trStr = transfer(temp,wordList,check);
while(!trStr.equals(""))
{
q.add(trStr);
check.add(trStr);
if(trStr.equals(endWord))
{
return level+1;
}
total++;
trStr = new String(transfer(temp,wordList,check));
}
if(cur == 0)
{
cur = total;
total = 0;
level++;
}
}
return 0;
}
public String transfer(String str1, Set<String> wordList, Set<String> check)
{
String res = "";
Iterator iter = wordList.iterator();
while(iter.hasNext())
{
String str2 = (String)iter.next();
if(check.contains(str2))
{
continue;
}
if(isOK(str1,str2))
{
return str2;
}
}
return res;
}
public boolean isOK(String str1, String str2)
{
int i = 0;
int res = 0;
//System.out.println(str1 + " " + str2);
while(i < str1.length())
{
if(str1.charAt(i) != str2.charAt(i))
{
res++;
if(res > 1) return false;
}
i++;
}
if(res == 0) return false;
return true;
}
}
然后介绍下CODE GANKER的办法。
比如"a",他最多能有25个edge就是"b","c","d".."z".
比如"ab",最多是"aa","ac","ad"..."bb","cb","db"..
总之一次只能改变1个字母嘛,每一位有26种选择(算上它自己)。
因为单词长度不会很长,所以可以穷举。。每位每次变一个,看在不在LIST里。。在就说明可以转化。
把中间的判断部分改一下就行了。。
public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList)
{
Queue<String> q = new LinkedList<String>();
Set<String> check = new HashSet<String>();
q.add(beginWord);
check.add(beginWord);
int cur = 1;
int level = 1;
int total = 0;
while(!q.isEmpty())
{
String temp = q.poll();
cur--;
for(int i = 0; i < temp.length();i++)
{
char[] tempArray = temp.toCharArray();
for(char j = 'a'; j <= 'z';j++)
{
tempArray[i] = j;
String newString = new String(tempArray);
if(!check.contains(newString) && wordList.contains(newString))
{
if(newString.equals(endWord)) return level+1;
check.add(newString);
q.add(newString);
total++;
}
}
}
if(cur == 0)
{
cur = total;
total = 0;
level++;
}
}
return 0;
}
}
看一刷写的记录,我一刷居然用的DFS,然后TLE。我完全记不得当时的情况,对于当时唯一还存留的印象就是我当时的姓名和性别。
肯定有DFS的做法,介于我现在做题把头做大了(胖头鱼YYF),就不看了。。
三刷。
我曾经想象过很多次这个时刻,被拒的时刻,可它来临的时候,我依然觉得很难过。
这个题印象比较深,是BFS的图形题。
搜索的时候有一个桥办法是26个字母轮一遍。其实应该试试如何正儿八经做。。
时间复杂度……
depth = n, brach = 26 so.. 26 ^ n
这是2个内部loop。 外面还有个while loop,可能所有单词都要来一遍,所以n
Time Complexity: O(n(26^n))
空间复杂度……
Queue + tempString(charArray) = O(N)? 是这样吧。。 我对这个概念混淆很严重,比如类似于combination中间产生的tempList,倘若不是为了迭代,如果最终要加入结果集,那算不算占用了空间。。毕竟最终结果本身就是O(n * 2^n)
Space Complexity: O(n)
public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
if (beginWord.equals(endWord)) return 2;
Queue<String> q = new LinkedList<>();
q.add(beginWord);
int res = 1;
int left = 1;
int total = 0;
while (!q.isEmpty()) {
String str = q.poll();
for (int i = 0; i < str.length(); i++) {
char[] chArray = str.toCharArray();
for (char j = 'a'; j <= 'z'; j++) {
chArray[i] = j;
String s = new String(chArray);
if (s.equals(endWord)) {
return res + 1;
}
if (wordList.contains(s)) {
wordList.remove(s);
q.offer(s);
total++;
}
}
}
left--;
if (left == 0) {
left = total;
total = 0;
res++;
}
}
return 0;
}
}
看看递归。
网上的2头同时search,这样每次从少的那边找,不过要多建俩set
Time Complexity O(n * 26^n)
Space: 两个SET,运行过程中的SETS,charArray O(n) + O(n) + O(n) + O(k) = O(n)
觉得运行过程中的SET算一个,比如用一个全局变量。。。每次clear。。
public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
if (beginWord.equals(endWord)) return 2;
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add(beginWord);
set2.add(endWord);
wordList.remove(beginWord);
wordList.remove(endWord);
return bfs(wordList, set1, set2, 2);
}
public int bfs(Set<String> wordList, Set<String> set1, Set<String> set2, int depth) {
Set<String> nextLevel = new HashSet<>();
for (String s: set1) {
for (int i = 0; i < s.length(); i++) {
char[] chArray = s.toCharArray();
for (char j = 'a'; j <= 'z'; j++) {
chArray[i] = j;
String tempS = new String(chArray);
if (set2.contains(tempS)) return depth;
if (wordList.contains(tempS)) {
wordList.remove(tempS);
nextLevel.add(tempS);
}
}
}
}
if (nextLevel.size() == 0) return 0;
if (nextLevel.size() <= set2.size()) {
return bfs(wordList, nextLevel, set2, depth + 1);
} else {
return bfs(wordList, set2, nextLevel, depth + 1);
}
}
}

浙公网安备 33010602011771号