leetcode127之单词接龙(无向图的构建)
无向图的构建与遍历
思路一:第一眼看到这个题,想到的解法是递归回溯,和最小基因变化很类似,因此编写代码如下:
import java.util.List;
class Solution {
//典型的回溯问题,每次遍历字典找出未对比过的,然后标记,进入下一层,然后再回来取消标记
int min=Integer.MAX_VALUE;
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
boolean[] used=new boolean[wordList.size()];
dfs(beginWord,endWord,wordList,0,used);
return min==Integer.MAX_VALUE?0:min+1;
}
private void dfs(String beginWord, String endWord, List<String> wordList, int level, boolean[] used) {
//terminator
if(beginWord.equals(endWord)){
min=Math.min(min,level);
return;
}
for(int i=0;i<wordList.size();i++){
if(used[i]==false){
int count=0;
for (int j=0;j<beginWord.length();j++){
if(beginWord.charAt(j)!=wordList.get(i).charAt(j))
count++;
if(count>1)
break;
}
if(count==1){
used[i]=true;
dfs(wordList.get(i),endWord,wordList,level+1,used);
used[i]=false;
}
}
}
}
}
然而结果是超出时间限制,只有22 / 43 个通过测试用例。于是看题解,得到以下思路:构建无向连接图,然后广度遍历
class Solution {
//构建无向连接图,然后广度遍历
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
HashSet<String> hashSet = new HashSet(wordList);
HashMap<String, List<String>> hashMap = new HashMap<>();
hashSet.add(beginWord);
for (String s : hashSet) {
List<String> list = new LinkedList<>();
for (int i = 0; i < s.length(); i++) {
char x = s.charAt(i);
for (char c = 'a'; c <= 'z'; c++) {
if (c == x)
continue;
String tmp = (i > 0 ? s.substring(0, i) : "") + c + (i + 1 < s.length() ? s.substring(i + 1, s.length()) : "");
if (hashSet.contains(tmp))
list.add(tmp);
}
}
hashMap.put(s, list);
}
Set<String> used = new HashSet<>();
Queue<String> queue = new ArrayDeque();
queue.add(beginWord);
int level = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
String s = queue.poll();
if (!used.contains(s)) {
used.add(s);
if (s.equals(endWord))
return level + 1;
for (String x : hashMap.get(s))
queue.add(x);
}
}
level++;
}
return used.contains(endWord)?level:0;
}
}
这里构建无向图采用的是HashMap,key值设为当前节点,Value通过链表定义其邻接点,然后进行遍历与记录。
提交正确解后发现时间只击败了46%的人,遂去看最快的代码,发现用到的是一个双向搜索策略(题解中也有),而且代码更精炼,这里也贴一下记录
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> beginSet = new HashSet<>();
Set<String> endSet = new HashSet<>();
beginSet.add(beginWord);
endSet.add(endWord);
Set<String> dict = new HashSet<>(wordList);
if(!dict.contains(endWord)) return 0;
return search(beginSet, endSet, dict, 1);
}
private int search(Set<String> beginSet, Set<String> endSet, Set<String> dict, int cnt){
if(beginSet.isEmpty() || endSet.isEmpty()) return 0;
cnt++;
dict.removeAll(beginSet);
Set<String> nextSet = new HashSet<>();
for(String str : beginSet){
char[] chs = str.toCharArray();
for(int i = 0; i < chs.length; i++){
char c = chs[i];
for(char j = 'a'; j <= 'z'; j++){
chs[i] = j;
String tmp = new String(chs);
if(!dict.contains(tmp)) continue;
if(endSet.contains(tmp)) return cnt;
nextSet.add(tmp);
}
chs[i] = c;
}
}
return nextSet.size() > endSet.size() ? search(endSet, nextSet, dict, cnt) : search(nextSet, endSet, dict, cnt);
}
}