c++ 实现word ladder



leetcode的原题:

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

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.


题意就是在一个单词的集合在中找出一个最短的序列,每次只改变一个字母,从初始单词得到目标单词。


首先感觉很明显要用到广搜。从初始单词开始,把每种变换的可能枚举出来压入队列,然后再把队列中的单词做同样的操作,找到目标单词则返回。这个地方可以用两个整形变量来记录循环的次数,变量lev1记录当前循环的单词数,lev2记录新的变换可能数。每当lev1为0时表明进入下一层变换,res++,lev1赋值为lev2。

int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
	if (beginWord == endWord)
		return 0;
	int lev1 = 1, lev2 = 0, res = 0;
	queue<string>que;
	unordered_set<string>visited;
	que.push(beginWord);
	while (!que.empty())
	{
		string word = que.front();
		que.pop();
		--lev1;
		for (unsigned int i = 0; i < word.size(); ++i)
		{
			for (auto j = 0; j < 26; ++j)
			{
				string newWord = word;
				newWord[i] = 'a' + j;
				if (newWord != word)
				{
					if (newWord == endWord)
						return res + 2;
					if (wordDict.find(newWord) != wordDict.end() && visited.find(newWord) == visited.end())
					{
						++lev2;
						wordDict.erase(newWord);
						que.push(newWord);
						visited.insert(newWord);
					}
				}
			}
		}
		if (!lev1)
		{
			++res;
			lev1 = lev2;
			lev2 = 0;
		}
	}
	return 0;
}

这里有个地方注意一下,每次找到一个newWord后,可以在dict中把newWord erase掉,因为求的是最短序列,以后不会再用到这个单词。在leetcode oj上效率提高了几十个ms,不过还是花了467ms。


下面说一个优化了不少的办法,就是从两头同时开始进行查找。


用两个unordered_set来保留中间的生成的单词,然后再用他们生成新的单词集合,再进行查找。用这个办法leetcode上只花了81ms。

int ladderLength2(string beginWord, string endWord, unordered_set<string>& wordDict) {
	unordered_set<string> beginSet, endSet, *set1, *set2;
	int res = 1;
	beginSet.insert(beginWord);
	endSet.insert(endWord);
	while (!beginSet.empty() && !endSet.empty())
	{
		if (beginSet.size() <= endSet.size())
		{
			set1 = &beginSet;
			set2 = &endSet;
		}
		else
		{
			set1 = &endSet;
			set2 = &beginSet;
		}
		++res;
		unordered_set<string>tmp;
		for (auto cur : *set1)
		{
			string tmpcur = cur;
			for (auto &i : tmpcur)
			{
				char c = i;
				for (auto j = 0; j < 26; ++j)
				{
					i = j + 'a';
					if (set2->find(tmpcur) != set2->end())
						return res;
					if (wordDict.find(tmpcur) != wordDict.end())
					{
						tmp.insert(tmpcur);
						wordDict.erase(tmpcur);
					}
				}
					i = c;
				//tmpcur = cur;
			}
		}
		swap(tmp, *set1);
	}
	return 0;
}

这里遇到一个有意思的事情,我最开始还原tmpcur用的是将cur给tmpcur重新赋值,但是在oj上会出现wa,但是同样的例子在我自己电脑上调试是可以过的。看来oj上应该对这里进行了优化,tmpcur第二次赋值为cur时并没有重新读取cur的值,而是因为之前tmpcur = cur 所以直接就读了存tmpcur的寄存器,即将tmpcur赋值给了tmpcur。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值