leetcode word ladder II

word ladder I 在看答案的基础上,搞懂了,主要是利用BFS,广度遍历,同时是几个辅助空间的构造,两个队列,承载每次在dict 里面找到的单词并作为下一次循环查找的单词。注意的是每次放进来的单词是必须没有访问过的,代码如下:

class Solution {
public:
   int ladderLength(string start, string end, set<string> &dict){
		queue<string> current,next;
		unordered_map<string,string> record; // 记录dict里面的键是由哪个单词转换而来的。感觉在这里没有用到,但是如果要输出最短路径就用到了
		unordered_set<string> visited;// 访问过的字符串存储下来
		bool flag = false; // 找到了就终止,因为是广度,所以可以保证是最短
		int level = 0;
		current.push(start); // 从第一个开始,第一层上

		while(!current.empty() && !flag)
		{
			level++; 
			while(!current.empty() && !flag) // 保证next层里面的数都穷
			{
			string curWord (current.front()); // 第一个单词出队,开始找下家
			current.pop();
			for(int i = 0;i < curWord.size();i++) // 按个字符进行替换
			{
				for(char c = 'a';c <= 'z';c++) // 这是题目中告诉你都是小写字母的原因,你可以从所有的小写字母中替换,是否可以优化,从dict里面取单词
				{
					string subWord (curWord);
					if(c == subWord[i])
						continue;
					subWord[i] = c;
					if(subWord == end)
					{
						flag = true;
						record[subWord] = curWord;// 为了存储最短路径来的,本题目中可以不用
						break;
					}
					if(dict.count(subWord) > 0 && visited.count(subWord) == 0)
					{
						next.push(subWord);// 下一层开始从这个队列开始,这里可能会放很多单词, hot ,cit hig 
						visited.insert(subWord);
						record[subWord] = curWord;  // 为了存储最短路径来的,本题目中可以不用
					}
				}
			}
			}
			swap(next,current);
		}
		if(flag)
			return level+1;
		else
			return 0;
   }

};
其中record 变量是可以记录最短路径,并且将其输出的这样的辅助空间,本以为II就是让你输出,这样就可以直接应用了,但是II 来狠的,是让你输出所有最短路径,那么就不能单纯输出一条,这个时候遍历的时候就要做一些限制,想靠自己的力量在I的基础上进行更改:

更改点:

1)遇到有结尾之后,flag 不能在里层循环里面当成判断条件为true,否则不会有下一条路径。

2)visited 不能是全部的单词是否访问,这在一条路径中是可以的,但是多条路径的时候,visited要是上一层路径没有访问过的即可,当前层是可以出现重复单词的

例子:visited 变成了二维数组,这样占据了空间

Input: "red", "tax", ["ted","tex","red","tax","tad","den","rex","pee"]
Output: [["red","ted","tad","tax"],["red","ted","tex","tax"]]
Expected: [["red","ted","tad","tax"],["red","ted","tex","tax"],["red","rex","tex","tax"]]
3) 形成路径的时候,要有额外的函数进行支撑

class Solution {
public:
   vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
		vector<string> current,next;
		multimap<string,string> record; // 记录dict里面的键是由哪个单词转换而来的。感觉在这里没有用到,但是如果要输出最短路径就用到了
		vector<vector<string>> results;
		vector<string>result;
		vector<vector<string>> visited;// 要所有的,所以访问过的字符串要智能写,辨别每一层的	
		vector<string> dump;
		dump.push_back(start);
		visited.push_back(dump); // 第一层上无判重值
		dump.clear();
		bool flag = false; // 找到了就终止,因为是广度,所以可以保证是最短
		int level = 0;
		current.push_back(start); // 从第一个开始,第一层上

		while(!current.empty() && !flag)
		{
			level++; 
			while(!current.empty()) // 保证next层里面的数都穷
			{
			string curWord (current.back()); // 第一个单词出队,开始找下家
			current.pop_back();
			for(int i = 0;i < curWord.size();i++) // 按个字符进行替换
			{
				for(char c = 'a';c <= 'z';c++) // 这是题目中告诉你都是小写字母的原因,你可以从所有的小写字母中替换,是否可以优化,从dict里面取单词
				{
					string subWord (curWord);
					if(c == subWord[i])
						continue;
					subWord[i] = c;
					if(subWord == end)
					{
						flag = true;
						result.push_back(end);
						getResult2(record,results,result,start,curWord);
						result.clear();
						continue;
						// 这里就不break l,让其继续循环
					}
					if((dict.count(subWord) > 0 && ( level == 1||find(visited[level-2].begin(),visited[level-2].end(),subWord) == visited[level-2].end()))) // 在上一层里面找是否有访问过的,当前层不算
					{
						if(find(next.begin(),next.end(),subWord) == next.end())
							next.push_back(subWord);//在作为下一层要进行处理的单词,不能出现重复的
						if(visited.size() <= level )
							visited.push_back(dump); // 防止溢出
						visited[level].push_back(subWord);
						record.insert(make_pair(subWord,curWord));  // 为了存储最短路径来的,本题目中可以不用
					}
				}
			}
			}
			swap(next,current);
		}
		return results;
   }

   /*void getResult(unordered_map<string,string> record,vector<vector<string>> &results,string end,string start)
   {
	   vector<string> result;
	   vector<string> finalR;
	   string keyStr = end;	
	   result.push_back(end);
	   while(record[keyStr] != start)
	   {
		   result.push_back(record[keyStr]);
		   keyStr = record[keyStr];
	   }
	   result.push_back(start);
	   auto iter = result.rbegin();
	   for(;iter != result.rend();iter++)
		   finalR.push_back(*iter);
	   results.push_back(finalR);	   
   }*/
   // 这个递归是可以实现目的的!但是memeory 超时
   void getResult2(multimap<string,string> record,vector<vector<string>> &results,vector<string> &result,string start,string keyStr)
   {
	   result.push_back(keyStr);
	   if(keyStr == start)
	   {
		   reverse(result.begin(),result.end());
		   results.push_back(result);
		   return;
	   }
	   auto beg = record.lower_bound(keyStr);
	   auto end = record.upper_bound(keyStr);
	   while(beg != end)
	   {
		   getResult2(record,results,result,start,beg->second);
		   result.pop_back();
		   ++beg;
	   }
   }
};

但是上面的虽然符合条件,竟然memeory limited。。。。

继续优化,看了答案才知道,visited 可以不用设置二维数组,只要将其位置换一下即可,这个是想法的差距!

class Solution {
public:
   vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
		vector<string> current,next;
		multimap<string,string> record; // 记录dict里面的键是由哪个单词转换而来的。感觉在这里没有用到,但是如果要输出最短路径就用到了
		vector<vector<string>> results;
		vector<string>result;
		vector<string> visited;// 要所有的,所以访问过的字符串要智能写,辨别每一层的 这里占内存了?	
		//vector<string> dump;
		//dump.push_back(start);
		//visited.push_back(dump); // 第一层上无判重值
		//dump.clear();
		bool flag = false; // 找到了就终止,因为是广度,所以可以保证是最短
		int level = 0;
		current.push_back(start); // 从第一个开始,第一层上

		while(!current.empty() && !flag)
		{
			level++; 
			while(!current.empty()) // 保证next层里面的数都穷
			{
			for(auto word:current)
					visited.push_back(word);  // 将visited 放在最前面,就不用level去判断了!你要的只是上一层而已
			string curWord (current.back()); // 第一个单词出队,开始找下家
			current.pop_back();
			for(int i = 0;i < curWord.size();i++) // 按个字符进行替换
			{
				for(char c = 'a';c <= 'z';c++) // 这是题目中告诉你都是小写字母的原因,你可以从所有的小写字母中替换,是否可以优化,从dict里面取单词
				{
					string subWord (curWord);
					if(c == subWord[i])
						continue;
					subWord[i] = c;
					if(subWord == end)
					{
						flag = true;
						result.push_back(end);
						getResult2(record,results,result,start,curWord);
						result.clear();
						continue;
						// 这里就不break l,让其继续循环
					}
					if(find(visited.begin(),visited.end(),subWord)== visited.end() &&(dict.count(subWord) > 0) ) // 在上一层里面找是否有访问过的,当前层不算
					{
						if(find(next.begin(),next.end(),subWord) == next.end())
							next.push_back(subWord);//在作为下一层要进行处理的单词,不能出现重复的
						record.insert(make_pair(subWord,curWord));  // 为了存储最短路径来的,本题目中可以不用
					}
				}
			}
			}
			swap(next,current);
		}
		return results;
   }

  
   // 这个递归是可以实现目的的!但是memeory 超时
   void getResult2(multimap<string,string> record,vector<vector<string>> &results,vector<string> &result,string start,string keyStr)
   {
	   result.push_back(keyStr);
	   if(keyStr == start)
	   {
		   reverse(result.begin(),result.end());
		   results.push_back(result);
		   return;
	   }
	   auto beg = record.lower_bound(keyStr);
	   auto end = record.upper_bound(keyStr);
	   while(beg != end)
	   {
		   getResult2(record,results,result,start,beg->second);
		   result.pop_back();
		   ++beg;
	   }
   }
};

但是这样更改后,仍然超时,没办法,继续优化,既然current 我目前仍然是当队列来处理的,遍历一个pop一个,可能费时,所以将其全部遍历之后一次性clear 再与next 交换,利用for(auto word:currenword) 结构更改如下:
class Solution {
public:
   vector<vector<string>> findLadders(string start, string end, set<string> &dict) {
		vector<string> current,next;
		multimap<string,string> record; // 记录dict里面的键是由哪个单词转换而来的。感觉在这里没有用到,但是如果要输出最短路径就用到了
		vector<vector<string>> results;
		vector<string>result;
		vector<string> visited;// 要所有的,所以访问过的字符串要智能写,辨别每一层的 这里占内存了?	
		//visited.push_back(dump); // 第一层上无判重值
		bool flag = false; // 找到了就终止,因为是广度,所以可以保证是最短
		current.push_back(start); // 从第一个开始,第一层上

		while(!current.empty() && !flag)
		{ 
			for(auto word:current)
					visited.push_back(word); // 将visited 放在最前面,就不用level去判断了!你要的只是上一层而已
			for(auto curWord:current)
			{
				//string curWord (current.back()); // 第一个单词出队,开始找下家 不要每次都pop,
				//current.pop_back();
				for(int i = 0;i < curWord.size();i++) // 按个字符进行替换
				{
					for(char c = 'a';c <= 'z';c++) // 这是题目中告诉你都是小写字母的原因,你可以从所有的小写字母中替换,是否可以优化,从dict里面取单词
					{
						string subWord (curWord);
						if(c == subWord[i])     continue;
						subWord[i] = c;
						if(subWord == end)
						{
							flag = true;
							record.insert(make_pair(subWord,curWord));
							continue;
							// 这里就不break l,让其继续循环
						}
						if(find(visited.begin(),visited.end(),subWord)== visited.end() &&(dict.count(subWord) > 0) ) // 在上一层里面找是否有访问过的,当前层不算
						{
							if(find(next.begin(),next.end(),subWord) == next.end())
								next.push_back(subWord);//在作为下一层要进行处理的单词,不能出现重复的
							record.insert(make_pair(subWord,curWord));  // 为了存储最短路径来的,本题目中可以不用
						}
					}
				}
			}
			current.clear();
			swap(next,current);
		}
		if(flag)
			getResult2(record,results,result,start,end);// 把建立路径的过程搞在外面来,不在里面处理
		return results;
   }

  
   // 这个递归是可以实现目的的!但是memeory 超时
   void getResult2(multimap<string,string> record,vector<vector<string>> &results,vector<string> &result,string start,string keyStr)
   {
	   result.push_back(keyStr);
	   if(keyStr == start)
	   {
		   reverse(result.begin(),result.end());
		   results.push_back(result);
		   return;
	   }
	   auto beg = record.lower_bound(keyStr);
	   auto end = record.upper_bound(keyStr);
	   while(beg != end)
	   {
		   getResult2(record,results,result,start,beg->second);
		   result.pop_back();
		   ++beg;
	   }
   }
};

至此,已经跟答案相差无几了,但是。。仍然超时,那么就只能归结于是record 结构选择的问题了,我用multimap 实现的,实际上可以用map<string,vector<string>>来实现multimap ,那么是这个的区别?


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值