【Leetcode】Word Ladder II

题目链接:https://leetcode.com/problems/word-ladder-ii/

题目:

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 intermediate word must exist in the word list

For example,

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

Return

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

Note:

  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
思路:
http://blog.csdn.net/yeqiuzs/article/details/51872443  解法的基础上修改: 改为需要保存遍历过程中的路径,要找到所有最优解
可以有两种方法:我的做法是用队列保存 当前遍历结点队列(即代码中的queue)每一个结点的一条追踪路径。因为都是队列,可以保证一致的顺序性;另一种是用hashmap保存每个结点的邻接表,建立邻接表后,先bfs计算出最短路径,然后dfs邻接表得到所有解。

用第一种方法,直接在word ladder 基础上修改,虽然能得到正确解,但在大数据下会超时,考虑优化。  很容易就发现,当word list集合过大的时候,越遍历到后面原来的做法仍然需要遍历整个wordlist,实际上是没有必要的。因为如果之后存在最优解,之前遍历过的结点不会出现在以后,否则会形成循环,而循环是可以删去的。  所以增加一个变量currLevel记录当前遍历到哪一层了,当进入下一层时,则将当前层次已经遍历过的结点从wordlist中删去,下一层没必要还遍历这些删去的结点了。要注意,一定要在进入下一层时,才删除(剪枝),因为在相同层次遍历时删除,可能会丢掉最优解,比如图中存在两条最优解:1->2->3->4, 1->5->3->4,其中2,5结点是同一层,如果在第一次遍历到结点3后就删除3,则第二条路径1-5就到达不了3了,所以只有当结点2、5都到了3后进入结点4之前删除3才不会丢弃解。

算法:
	public List<List<String>> findLadders(String beginWord, String endWord, Set<String> wordList) {
		Queue<List<String>> tracks = new LinkedList<List<String>>(); // 保存遍历过程中可能到达end结点的路径
		Queue<Word> queue = new LinkedList<Word>();
		List<List<String>> res = new ArrayList<List<String>>();
		Set<String> remove = new HashSet<String>();
		int min = Integer.MAX_VALUE;// 最短距离
		int currLevel = 1; // 当前遍历的层数

		queue.offer(new Word(beginWord, 1));
		List<String> t = new ArrayList<String>();
		t.add(beginWord);
		tracks.offer(t);
		wordList.add(endWord);

		while (!queue.isEmpty()) {
			Word w = queue.poll();
			currLevel = Math.max(currLevel, w.steps);// 更新当前遍历层数

			List<String> track = tracks.poll();
			if (w.word.equals(endWord) && w.steps <= min) { // 如果到了目的结点,且遍历层数小于或等于min
				min = w.steps;
				res.add(track);
				continue;
			}
			if (w.steps > min) // 如果大于min则之后的遍历不可能还有最短距离这么长的路径了
				break;

			char[] ws = w.word.toCharArray();

			for (int i = 0; i < w.word.length(); i++) {
				char tmp = ws[i];
				for (char j = 'a'; j < 'z'; j++) {
					if (tmp == j) // 不能原地循环
						continue;
					ws[i] = j;
					String ns = new String(ws);
					if (wordList.contains(ns)) {
						queue.offer(new Word(ns, w.steps + 1));
						List<String> nextTrack = new ArrayList<String>(track);
						nextTrack.add(ns);
						tracks.offer(nextTrack);
						if (!ns.equals(endWord))
							remove.add(ns);
					}
				}
				ws[i] = tmp;
			}
			if (!queue.isEmpty() && queue.peek().steps > currLevel) {// 将进入下一层
				for (String r : remove) // 则将以后不会访问的结点删去 ,剪枝
					wordList.remove(r);
			}

		}
		return res;
	}

	class Word {
		int steps;
		String word;

		public Word(String word, int steps) {
			this.word = word;
			this.steps = steps;
		}
	}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值