2018-10-02 23:46:38
问题描述:
问题求解:
显然是个解空间遍历问题,每次修改其中一位,由于步长是1,所以可以使用BFS进行解空间的遍历。
解法一、单向BFS
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> set = new HashSet<>();
for(String i : wordList) set.add(i);
if (!set.contains(endWord)) return 0;
if (beginWord.equals(endWord)) return 1;
Queue<String> queue = new LinkedList<>();
Set<String> used = new HashSet<>();
int step = 0;
queue.add(beginWord);
used.add(beginWord);
while(!queue.isEmpty()) {
int size = queue.size();
step++;
for (int i = 0; i < size; i++) {
char[] chs = queue.poll().toCharArray();
for (int j = 0; j < chs.length; j++) {
char ch = chs[j];
for (char c = 'a'; c <= 'z'; c++) {
if (c == ch) continue;
chs[j] = c;
String then = new String(chs);
if (then.equals(endWord)) return step + 1;
if (!set.contains(then) || used.contains(then)) continue;
queue.add(then);
used.add(then);
}
chs[j] = ch;
}
}
}
return 0;
}
这里有个简单的优化,就是不使用used数组,而是每次使用扩展一个数前,将其从set中去除来防止再次扩展这个数。
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> set = new HashSet<>();
for(String i : wordList) set.add(i);
if (!set.contains(endWord)) return 0;
if (beginWord.equals(endWord)) return 1;
Queue<String> queue = new LinkedList<>();
int step = 0;
queue.add(beginWord);
while(!queue.isEmpty()) {
int size = queue.size();
step++;
for (int i = 0; i < size; i++) {
char[] chs = queue.poll().toCharArray();
for (int j = 0; j < chs.length; j++) {
char ch = chs[j];
for (char c = 'a'; c <= 'z'; c++) {
if (c == ch) continue;
chs[j] = c;
String then = new String(chs);
if (then.equals(endWord)) return step + 1;
if (!set.contains(then)) continue;
set.remove(then);
queue.add(then);
}
chs[j] = ch;
}
}
}
return 0;
}
解法二、双向BFS
单向的BFS是可以通过所有的用例的,但是本题中解空间还是比较庞大的,可以使用双向BFS来进一步的提高算法的时间复杂度。
从两边开始遍历,每次遍历一端,所以需要维护两个Set,这里不用Queue是为了方便实现。
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> set = new HashSet<>();
for(String i : wordList) set.add(i);
if (!set.contains(endWord)) return 0;
if (beginWord.equals(endWord)) return 1;
Set<String> q1 = new HashSet<>();
Set<String> q2 = new HashSet<>();
q1.add(beginWord);
q2.add(endWord);
int step = 0;
while (!q1.isEmpty() && !q2.isEmpty()) {
step++;
if (q1.size() > q2.size()) {
Set<String> tmp = q1;
q1 = q2;
q2 = tmp;
}
Set<String> cur = new HashSet<>();
for (String w : q1) {
char[] chs = w.toCharArray();
for (int i = 0; i < chs.length; i++) {
char ch = chs[i];
for (char c = 'a'; c <= 'z'; c++) {
if (c == ch) continue;
chs[i] = c;
String then = new String(chs);
if (q2.contains(then)) return step + 1;
if (!set.contains(then)) continue;
set.remove(then);
cur.add(then);
}
chs[i] = ch;
}
}
q1 = cur;
}
return 0;
}