leetcode 126. Word Ladder II

LeetCode单词梯难题解
本文详细解析LeetCode上难度较高的单词梯问题,通过广度优先搜索策略寻找从开始单词到结束单词的所有最短转换路径,并附带实现代码。

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord toendWord, such that:

  1. Only one letter can be changed at a time
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

For example,

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]

Return

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Note:

  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.

  • You may assume beginWord and endWord are non-empty and are not the same.

这道题是LeetCode最难的之一了,刚开始直接做这个没做Word Ladder,感觉还是过于复杂搞不定。于是先回去做127 Word Ladder,用广度优先搜索得到最短的转换次数(详见127word Ladder)。

在此基础上,很容易将返回层数改造成返回每一层搜索到的字符串List,得到每一层的List之后还是可以先做剪枝,因为得到的是从前往后的每个相邻层之间的转换,可以利用从后往前搜索,排除不能到达的字符串。

例如题目中的例子每层就得到:

hit

hot

dot,lot

dog,log

cog

最后逐层构造转换List即可。看到其他博客说最后构造用的dfs,这里我用的bfs,感觉更直观


AC代码,372 ms,还有可以优化的地方

class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, 
		List<String> wordList) {
  
	if(!wordList.contains(endWord)){
		return new ArrayList<List<String>>();
	}
	if(beginWord.equals(endWord)){
		List<List<String>> list = new ArrayList<List<String>>();
		List<String> strs = new ArrayList<String>();
		strs.add(beginWord);
		list.add(strs);
		return list;
	}
	if(compareTwoStr(beginWord,endWord)){
		List<List<String>> list = new ArrayList<List<String>>();
		List<String> strs = new ArrayList<String>();
		strs.add(beginWord);
		strs.add(endWord);
		list.add(strs);
		return list;
	}
    if(wordList.contains(beginWord)){
        wordList.remove(beginWord);
	}
	List<List<String>> list = new ArrayList<List<String>>();
	list =  ladders(beginWord,endWord,wordList);
	if(list.size() == 0){
		return list;
	}

	list = removeLadders(beginWord, endWord, wordList, list);
	if(list.size() == 0){
		return list;
	}
	
	
	List<List<String>> tempList = new ArrayList<List<String>>();
	tempList.add(new ArrayList<String>());
	tempList.get(0).add(beginWord);
	List<List<String>> tempList2 = new ArrayList<List<String>>();
	for(int i=1;i<list.size();i++){
		for(String str: list.get(i)){
			for(int j=0;j< tempList.size();j++){
				if(compareTwoStr(str, tempList.get(j).get(tempList.get(j).size()-1))){
					tempList2.add(new ArrayList<String>(tempList.get(j)));
					tempList2.get(tempList2.size()-1).add(str);
				}
			}
		}
		tempList.clear();
		tempList = new ArrayList<List<String>>(tempList2);
		tempList2.clear();
	}
	
	return tempList;
 }
	

	public List<List<String>> ladders(String beginWord, String endWord, List<String> wordList) {
		List<List<String>> list = new ArrayList<List<String>>();
		list.add(new ArrayList<String>());
		list.get(0).add(beginWord);
		List<String> visited = new ArrayList<String>();
		List<String> remain = new ArrayList<String>(wordList);
		visited.add(beginWord);
		int index = 0;
		int visitLen = 1;
		int count = 1;
		while(!visited.contains(endWord)){
			boolean found = false;
			list.add(new ArrayList<String>());
			for(int i=index;i<index+visitLen;i++){
				for(int j=remain.size()-1 ;j>=0; j--){
					if(compareTwoStr(remain.get(j), visited.get(i)) 
							&& !visited.contains(remain.get(j))){
						visited.add(remain.get(j));
						list.get(list.size()-1).add(remain.get(j));
						found = true;
						remain.remove(j);
					}
				}
				
			}
			if(!found){
				list.clear();
				return list;
			}
			count++;
			index += visitLen;
			visitLen = visited.size() - index;
		}
		
		for(int i= list.get(list.size()-1).size()-1 ;i>=0;i--){
			if(!list.get(list.size()-1).get(i).equals(endWord)){
				list.get(list.size()-1).remove(i);
			}
		}
		return list;
        
    }
	

	//辅助函数,判断两串只相差1字符
	public boolean compareTwoStr(String str1,String str2){
		int count = 0;
		for(int i=0;i<str1.length();i++){
			if(str1.charAt(i) != str2.charAt(i)){
				count++;
				if(count>1)
					return false;
			}
		}
		return count == 1;
	}
	
	//remove
	public List<List<String>> removeLadders(String beginWord,
			String endWord, List<String> wordList,List<List<String>> list) {
		for(int i=list.size()-1;i>0;i--){
			for(int j=list.get(i-1).size()-1;j>=0;j--){
				boolean canReach = false;
				for(String str2 : list.get(i)){
					if(compareTwoStr(list.get(i-1).get(j), str2)){
						canReach = true;
						break;
					}
				}
				if(!canReach){
					list.get(i-1).remove(j);
				}
			}
		}
		 return list;
	}
	
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值