题目描述:
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出: 5
解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: 0
解释: endWord “cog” 不在字典中,所以无法进行转换。
比较简单的BFS算法,但是你需要注意的是防止出现死循环,因此我设置了 一个Set集合,用于存储的是所有节点,所谓BFS指的是宽度优先搜索,设置一个队列,存放的是一行行的值,isOneDif是取出所有与该节点只有一个字符之差的字符,代码如下
class Solution {
public boolean isOnDif(String s,String t){
int dif = 0;
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i) != t.charAt(i)){
dif++;
}
if(dif > 1 ){
return false;
}
}
return dif == 1;
}
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//如果不包含那么就返回0
if(!wordList.contains(endWord)){
return 0;
}
int deep = 1;
Queue<String> temQueue = new LinkedList<>();
Set<String> temSet = new HashSet<>();
temSet.add(beginWord);
temQueue.offer(beginWord);
while (!temQueue.isEmpty()) {
int size = temQueue.size();
deep ++;
while (size > 0) {
size--;
String temString = temQueue.poll();
//取出第一层,然后我们开始寻找与之只有一个字母的区别的字母
for (String string : wordList) {
if(isOnDif(temString, string) && !temSet.contains(string)){
if(string.equals(endWord)){
return deep;
}
temSet.add(string);
temQueue.offer(string);
}
}
}
}
return 0;
}
}
很显然排名不会很高,因为差不多使用的是暴力搜索,因此考虑优化
使用两头递归的方法,即:设置一个set为beginset保存的是一开始的初始单词设置一个set为endset为目的单词,worddic为给出的单词列表,其中也是set,一开始从beginset开始,设置一个temset,从beginset中寻找与之差一位的单词放入temset中,改进的代码思路:
从两边开始查找,每次都从比较小的开始寻找
自己实现的代码如下
class Solution {
public boolean isOnDif(String s,String t){
int dif = 0;
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i) != t.charAt(i)){
dif++;
}
if(dif > 1 ){
return false;
}
}
return dif == 1;
}
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
if(!wordList.contains(endWord)){
return 0;
}
Set<String> beginSet = new HashSet<>(Arrays.asList(beginWord));
Set<String> endSet = new HashSet<>(Arrays.asList(endWord));
Set<String> dic = new HashSet<>(wordList);
int step = 1;
while (!beginSet.isEmpty()) {
step++;
Set<String> temSet = new HashSet<>();
for (String string : beginSet) {
//在字典中删除beginset中包含的
dic.remove(string);
}
for (String string : beginSet) {
//相差一个,并且在dic中
for (String strings : dic) {
if(isOnDif(string, strings)){
temSet.add(strings);
if(endSet.contains(strings)){
return step;
}
}
}
}
if(temSet.size() < endSet.size()){
beginSet = temSet;
}else {
beginSet = endSet;
endSet = temSet;
}
}
return 0;
}}
排名靠前的代码
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 bfs(beginSet, endSet, dict, 0);
}
private int bfs(Set<String> beginSet, Set<String> endSet, Set<String> dict, int step){
if(beginSet.isEmpty() || endSet.isEmpty()) return 0;
step++;
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 old = chs[i];
for(char c = 'a'; c <= 'z'; c++){
chs[i] = c;
String next = new String(chs);
if(!dict.contains(next)) continue;
if(endSet.contains(next)) return step + 1;
nextSet.add(next);
}
chs[i] = old;
}
}
return nextSet.size() > endSet.size() ? bfs(endSet, nextSet, dict, step) : bfs(nextSet, endSet, dict, step);
}
}
看一下这位同志的思路
借用的就是这个思路