leetcode 127 Word Ladder

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, 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.

Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
方法1:我考虑用BFS解决,状态转移及停止判断均用isNext函数来处理
但结果超时,有哪位大神可以帮我解决一下???
#include<iostream>
#include<string>
#include<queue>
#include<map>
#include<unordered_set>
using namespace std;
struct node
{
	string str;
	int step;
};
bool isNext(string a,string b)//判断两个字符串是否是同长度只有一个位置不同
{
	int len=a.length(),count=0;
	for(int i=0;i<len;i++)
		if(a[i]!=b[i])
			count++;
	if(1==count)
		return true;
	return false;
}
int ladderLength(string start, string end, unordered_set<string> &dict)
{
	queue<node> QS;
	unordered_set<string>::iterator it;
	map<string,int> visited;
	for(it=dict.begin();it!=dict.end();it++)
		visited[*it]=false;//防止重复出现,避免死循环!
	node ns;
	ns.str=start;
	ns.step=0;
	QS.push(ns);//将起始字符串放入队列中
	while(!QS.empty())
	{
		node now=QS.front();
		QS.pop();
		if(isNext(now.str,end))
			return now.step;
		for(it=dict.begin();it!=dict.end();it++)//不用遍历26个字母,这样的效率已经很高了,为什么还会超时呢??????
			if(isNext(now.str,*it)&&!visited[*it])//先进队列的节点就有先找到目标节点的优势
			{
				visited[*it]=true;//入队时要标记防止重复访问
				node temp;
				temp.str=*it;
				temp.step=now.step+1;
				QS.push(temp);
			}
	}
	return 0;
}
int main(int argc,char *argv[])
{
	freopen("input.txt","r",stdin);
	string start,end,str;
	unordered_set<string> dict;
	int num;
	cin>>start>>end;
	cin>>num;
	while(num--)
	{
		cin>>str;
		dict.insert(str);
	}
	/*
	unordered_set<string>::iterator it;
	for(it=dict.begin();it!=dict.end();it++)
		cout<<*it<<" ";
	cout<<endl;
	*/
	cout<<ladderLength(start,end,dict)+2<<endl;
	return 0;
}
思考再三,超时的地方应该在isNext()函数上,每次试探都要判断两个字符串是否只有一个不同。
方法2:下面这种方法参考了http://www.cnblogs.com/TenosDoIt/p/3443512.html

这种题,肯定是每次改变单词的一个字母,然后逐渐搜索,很多人一开始就想到用dfs,其实像这种求最短路径、树最小深度问题bfs最适合,可以参考我的这篇博客bfs(层序遍历)求二叉树的最小深度。本题bfs要注意的问题:

  • 和当前单词相邻的单词是:对当前单词改变一个字母且在字典中存在的单词
  • 找到一个单词的相邻单词,加入bfs队列后,要从字典中删除,因为不删除的话会造成类似于hog->hot->hog的死循环。而删除对求最短路径没有影响,因为我们第一次找到该单词肯定是最短路径,即使后面其他单词也可能转化得到它,路径肯定不会比当前的路径短(如果要输出所有最短路径,则不能立即从字典中删除,具体见下一题)
  • bfs队列中用NULL来标识层与层的间隔,每次碰到层的结尾,遍历深度+1

我们利用和求二叉树最小深度层序遍历的方法来进行bfs,代码如下:                        


int ladderLength(string start,string end,unordered_set<string> &dict)
{
	queue<string> QS;
	QS.push(start);
	QS.push(" ");
	int res=1;
	while(!QS.empty())
	{
		string str=QS.front();
		QS.pop();
		if(str!=" ")
		{
			int strlen=str.length();
			for(int i=0;i<strlen;i++)
			{
				char tmp=str[i];
				for(char c='a';c<='z';c++)
				{
					if(c==tmp)
						continue;
					str[i]=c;
					if(str==end)
						return res+1;
					if(dict.find(str)!=dict.end())
					{
						QS.push(str);//入队
						dict.erase(str);//避免重复入队
					}
				}
				str[i]=tmp;//复原i位置,考虑下一个位置
			}
		}else if(QS.empty()==false)//到达当前层的末尾
		{
			res++;
			QS.push(" ");
		}
	}
	return 0;
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值