Leetcode 127. Word Ladder

Given two words (beginWord and endWord), and a dictionary’s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

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

Return 0 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.
Example 1:

Input:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]

Output: 5

Explanation: As one shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
return its length 5.

method 1 BFS

标准的BFS遍历代码,并且使用一个set记录已经单词列表中的单词,只有改变后的单词在这个范围内,才能压进队列

int ladderLength3(string beginWord, string endWord, vector<string>& wordList) {
	unordered_set<string> dirc(wordList.begin(), wordList.end());
	queue<string> q;
	q.push(beginWord);

	int cnt = 1;
	while (!q.empty()){
		int sz = q.size();
		while (sz-- > 0){
			string p = q.front(); q.pop();
			
			if (p == endWord) return cnt;

			dirc.erase(p);
			for (int i = 0; i < p.size(); i++)
			{
				char c = p[i];
				for (int k = 0; k < 26; k++){
					p[i] = 'a' + k;
					if (dirc.count(p)) {
						q.push(p);
					}
				}
				p[i] = c;
			}
		}

		cnt++;
	}

	return 0;
}

以下是第一版BFS代码,但超时了,因为在计算每个单词可以改变成的其他单词映射时,浪费了大量时间,与之相比,上面的代码只是每个单词的每个字符从‘a’-'z’依次改变,运算量相对小一点

bool canChange(string from, string to){
	int diff = 0;
	for (int i = 0; i < from.size(); i++){
		if (from[i] != to[i]) diff++;
		if (diff == 2) return false;
	}

	return true;
}

void fillLadder(string beginWord, vector<string>& wordList, unordered_map<string, vector<string>>& ladder){
	for (int i = 0; i < wordList.size(); i++)
	{
		if ( beginWord != wordList[i] && canChange(beginWord, wordList[i]))
			ladder[beginWord].push_back(wordList[i]);
	}

}

int ladderLength2(string beginWord, string endWord, vector<string>& wordList) {
	if (find(wordList.begin(), wordList.end(), endWord) == wordList.end()) return 0;

	unordered_map<string, vector<string>> ladder;
	fillLadder(beginWord, wordList, ladder);
	for (int i = 0; i < wordList.size(); i++)
		if(wordList[i] != endWord) fillLadder(wordList[i], wordList, ladder);

	queue<string> q;
	q.push(beginWord);

	int cnt = 1;
	while (!q.empty()){
		int sz = q.size();
		while (sz-- > 0){
			string p = q.front(); q.pop();
			if (ladder.count(p)){
				vector<string> changeList = ladder[p];
				for (int i = 0; i < changeList.size(); i++)
				{
					if (changeList[i] == endWord) return cnt + 1;
					else if(ladder.count(changeList[i])) q.push(changeList[i]);
				}

				ladder.erase(p);
			}
		}

		cnt++;
	}

	return 0;
}

method 2 Bidirectional Breadth First Search

以下为双端宽度优先搜索原理的解释:
The idea behind bidirectional search is to run two simultaneous searches—one forward from
the initial state and the other backward from the goal—hoping that the two searches meet in
the middle.The motivation is that b ^ (d / 2) + b ^ (d / 2) is much less than b^d.b is branch factor, d is depth. "

---- - section 3.4.6 in Artificial Intelligence - A modern approach by Stuart Russel and Peter Norvig

以下是双端优先搜索减少搜索量的示意图

具体操作中,

  1. 使用两个set,一个beginSet,一个endSet,每次总是从beignSet开始,所以每次循环开始,总是置大的set为beginSet
  2. 终止的条件是从beginSet开始的遍历中,当改变后的单词出现在endSet中时,即代表可以成功转变
  3. 总共转变的次数即层数
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
	if(find(wordList.begin(), wordList.end(),endWord) == wordList.end()) return 0;

    unordered_set<string> beginSet, endSet, visitedSet, dirc(wordList.begin(), wordList.end());
	beginSet.insert(beginWord);
	endSet.insert(endWord);

	int cnt = 1; 
	while (!beginSet.empty() && !endSet.empty()){
		if (beginSet.size() > endSet.size()){
			unordered_set<string> tmp = beginSet;
			beginSet = endSet;
			endSet = tmp;
		}

		unordered_set<string> tmp;
		for (string word : beginSet){
			for (int i = 0; i < word.size(); i++){
				char c = word[i];
				for (int k = 0; k < 26; k++){
					word[i] = 'a' + k;
					if (endSet.count(word)) return cnt + 1;
					if (!visitedSet.count(word) && dirc.count(word)){
						visitedSet.insert(word);
						tmp.insert(word);
					}
				}
				word[i] = c;
			}
		}

		cnt++;
		beginSet = tmp;
	}

	return 0;

}

summary

  1. BFS标准模板
  2. 对于BFS的问题,如果可以同时从两端开始遍历,并且他们都可以独立进行,那么使用Bidirectional Breadth First Search
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值