Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence frombeginWord to endWord, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the word list
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
BFS,从当前字串出发,下一层的字串有哪些,这个过程如果和集合里面的每一个字串遍历检测,复杂度O(N^2),大数据将超时,需要变换字母构造字串,然后检测构造的字串是不是在单词可用集合里面。
public int ladderLength(String beginWord, String endWord,Set<String> wordList)
{
if(beginWord.compareTo(endWord)==0)
return 0;
wordList.add(endWord);
wordList.remove(beginWord);
ArrayDeque<String> deque=new ArrayDeque<>();
HashMap<String, Boolean> hashmap=new HashMap<>(wordList.size());
for(String ss:wordList)
hashmap.put(ss, false);
deque.add(beginWord);
int count=1;
int level=0;
while(!deque.isEmpty())
{
count--;
if(count==0)
{
level++;
count=deque.size();
}
String s=deque.poll();
if(s.compareTo(endWord)==0)
return level;
int strlen=s.length();
for(int i=0;i<strlen;i++)
{
char c=s.charAt(i);
StringBuilder sb=new StringBuilder(s);
for(char cc='a';cc<c;cc++)
{
sb.setCharAt(i, cc);
String temp=sb.toString();
if(wordList.contains(temp)&&hashmap.get(temp)==false)
{
deque.add(temp);
hashmap.put(temp, true);
}
}
for(char cc=(char) (c+1);cc<='z';cc++)
{
sb.setCharAt(i, cc);
String temp=sb.toString();
if(wordList.contains(temp)&&hashmap.get(temp)==false)
{
deque.add(temp);
hashmap.put(temp, true);
}
}
}
}
return 0;
}
--------------------------------------------------------------------------------------------
双向BFS,速度会有很大提高
https://discuss.leetcode.com/topic/29303/two-end-bfs-in-java-31ms
每次搜索,轮流从beginset和endset进行(104ms)
public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
Set<String> beginSet = new HashSet<String>(), endSet = new HashSet<String>();
int len = 1;
int strLen = beginWord.length();
HashSet<String> visited = new HashSet<String>();
beginSet.add(beginWord);
endSet.add(endWord);
boolean change=false;
while (!beginSet.isEmpty() && !endSet.isEmpty())
{
if (change) {
Set<String> set = beginSet;
beginSet = endSet;
endSet = set;
}
Set<String> temp = new HashSet<String>();
for (String word : beginSet) {
char[] chs = word.toCharArray();
for (int i = 0; i < chs.length; i++) {
for (char c = 'a'; c <= 'z'; c++) {
char old = chs[i];
chs[i] = c;
String target = String.valueOf(chs);
if (endSet.contains(target)) {
return len + 1;
}
if (!visited.contains(target) && wordList.contains(target)) {
temp.add(target);
visited.add(target);
}
chs[i] = old;
}
}
}
beginSet = temp;
len++;
change=!change;
}
return 0;
}
}
每次搜索,轮流从beginset和endset选择元素数量较少的进行搜索(30ms)
"The
idea behind bidirectional search is to run two simultaneous searches—one forward from
the initial state and the other backward from the goal—hoping that the two searches meet in
the middle. The motivation is that b^(d/2) + b^(d/2) is much less than b^d. b is branch factor, d is depth.
the initial state and the other backward from the goal—hoping that the two searches meet in
the middle. The motivation is that b^(d/2) + b^(d/2) is much less than b^d. b is branch factor, d is depth.
public class Solution {
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
Set<String> beginSet = new HashSet<String>(), endSet = new HashSet<String>();
int len = 1;
int strLen = beginWord.length();
HashSet<String> visited = new HashSet<String>();
beginSet.add(beginWord);
endSet.add(endWord);
while (!beginSet.isEmpty() && !endSet.isEmpty()) {
if (beginSet.size() > endSet.size()) {
Set<String> set = beginSet;
beginSet = endSet;
endSet = set;
}
Set<String> temp = new HashSet<String>();
for (String word : beginSet) {
char[] chs = word.toCharArray();
for (int i = 0; i < chs.length; i++) {
for (char c = 'a'; c <= 'z'; c++) {
char old = chs[i];
chs[i] = c;
String target = String.valueOf(chs);
if (endSet.contains(target)) {
return len + 1;
}
if (!visited.contains(target) && wordList.contains(target)) {
temp.add(target);
visited.add(target);
}
chs[i] = old;
}
}
}
beginSet = temp;
len++;
}
return 0;
}
}