leetcode -day10 Word Ladder I II

1、


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.

分析:真的 一看这个题没有思路,想到每次改变一个字母,一直改下去,却不知道如何求最短。搜索得知,此题用到图的方法,广度优先遍历查找最短路径的方法,于是拿出《算法导论》看了一下图的广度优先遍历,大致思路是:用一个优先队列来保存访问过的点,每次取队列头元素,然后判断依次访问此元素的后继,然后将此元素出列,依次循环直到队列为空。此题相当于求最短路径,则需要判断到该结点的路径长度。

该题的思路:创建一个优先队列管理未遍历的结点,还有一个map,来保存遍历到的结点和距离。首先将start插入优先队列,然后开始循环,每次从优先队列取一个元素,并从其中删除,依次访问和此元素相差一个字母的值,查看此值是否在set中,如果不在或者在距离是否大于取出的元素的距离+1,则更新map,并插入此值,依次循环直到队列为空。

注意:其中有个很无聊的问题,看题目中转换次数为4,但是返回的长度为5,意思是加上了头尾。在执行过程中,当下面时,就显示2,不知道意思是如果start和end只有一个字母不同时,中间值无需字典中,感觉和题目要求中的Each intermediate word must exist in the dictionary不相符,很恶心。这样的话,应该在开始加一个判断start和end有几个字母不同的计算,如果为1,则直接返回2。

Input:"a", "c", ["a","b","c"]
Output:3
Expected:2

代码如下:

class Solution {
public:
	int ladderLength(string start, string end, unordered_set<string> &dict) {
		if(start.empty()||end.empty()||start.length()!=end.length()||start == end){
			return 0;
		}
		if(dict.empty()){
			return 0;
		}
		unordered_map<string,int> pathMap;
		pathMap.insert(make_pair(start,1));
		queue<string> strQue;
		strQue.push(start);
		string tempStr;
		while(!strQue.empty()){
			tempStr = strQue.front();
			strQue.pop();
			for(int i=0; i<tempStr.size(); ++i){
				for(char j='a'; j<='z'; ++j){
					if(tempStr[i] == j){
						continue;
					}else{
						string replaceStr = tempStr;
						replaceStr[i] = j;
						if(dict.find(replaceStr)!=dict.end() || replaceStr == end){
							if(!pathMap[replaceStr] ||  pathMap[replaceStr] && pathMap[replaceStr] > pathMap[tempStr]+1){
								if(replaceStr == end && pathMap[tempStr]+1 < 2){
									continue;
								}
								pathMap[replaceStr] = pathMap[tempStr]+1;
								strQue.push(replaceStr);
							}
						}
					}
				}
			}
		}
		return pathMap[end];
	}
};

2、Word Ladder II

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) 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"]

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.

分析:这个题和上题很像,但是特别复杂,我采用上次的思路,添加了一个unordered_map<string,vector<string>> prevStrVec来保存前缀,前缀都是从start到key的最短路径上的前一个词,然后再根据end向前追溯一直到start,每一条路径就是保存的路径,思路感觉没有问题,本地跑几个小数据也是对的,就是一直出错。

首次出错为:Output Limit Exceeded

输出超过限制,就是可能中间出现的循环折叠,没找到问题,然后设置了长度递归限制,当路径超过最短路径值时返回,此时又出错:

Time Limit Exceeded

大数据时,显示超时

代码如下:超时的代码:

class Solution {
public:
	vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
		//vector<vector<string> > paths;
		if(start.empty()||end.empty()||start.length()!=end.length()||start == end){
			return paths;
		}
		if(dict.empty()){
			return paths;
		}
		swap(start,end);
		unordered_map<string,int> pathMap;
		pathMap.insert(make_pair(start,1));
		queue<string> strQue;
		strQue.push(start);
		string tempStr;
		unordered_map<string,vector<string>> prevStrVec;
		while(!strQue.empty()){
			tempStr = strQue.front();
			strQue.pop();
			for(int i=0; i<tempStr.size(); ++i){
				for(char j='a'; j<='z'; ++j){
					if(tempStr[i] == j){
						continue;
					}else{
						string replaceStr = tempStr;
						replaceStr[i] = j;
						if(dict.find(replaceStr)!=dict.end() || replaceStr == end){
							if(!pathMap[replaceStr] ||  pathMap[replaceStr] && pathMap[replaceStr] >= pathMap[tempStr]+1){
								if(replaceStr == end && pathMap[tempStr]+1 < 2){
									continue;
								}
								if(pathMap[replaceStr]  && pathMap[replaceStr] > pathMap[tempStr]+1){
									prevStrVec[replaceStr].clear();
								}
								prevStrVec[replaceStr].push_back(tempStr);
								pathMap[replaceStr] = pathMap[tempStr]+1;
								strQue.push(replaceStr);
							}
						}
					}
				}
			}
		}
		if(pathMap[end]){
			vector<string> tempVec;
			tempVec.push_back(end);
			int shortLength = pathMap[end];
			findPaths(end,prevStrVec,tempVec,shortLength);
		}
		return paths;
	}
	void findPaths(string& end,unordered_map<string,vector<string>> &prevStrVec,vector<string> &path,int shortLength){
		vector<string> preEndVec = prevStrVec[end];
		if(preEndVec.empty()){
			paths.push_back(path);
			return;
		}
		if(path.size()==shortLength){
			return;
		}
		for(int j=0; j<preEndVec.size(); ++j){
			string preStr = preEndVec[j];
			vector<string> tempPath = path;
			tempPath.push_back(preStr);
			findPaths(preStr,prevStrVec,tempPath,shortLength);
		}
	}
	vector<vector<string> > paths;
};


改进,上述和第一题的区别是pathMap[replaceStr] 和pathMap[tempStr]+1 比较时,一个是>,一个是>=,后者将==的部分也放入队列了,这样时间复杂度高了好多,改进,==时不将数据放入队列,Accepted。

代码如下:

class Solution {
public:
	vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
		//vector<vector<string> > paths;
		if(start.empty()||end.empty()||start.length()!=end.length()||start == end){
			return paths;
		}
		if(dict.empty()){
			return paths;
		}
		swap(start,end);
		unordered_map<string,int> pathMap;
		pathMap.insert(make_pair(start,1));
		queue<string> strQue;
		strQue.push(start);
		string tempStr;
		unordered_map<string,vector<string>> prevStrVec;
		while(!strQue.empty()){
			tempStr = strQue.front();
			strQue.pop();
			for(int i=0; i<tempStr.size(); ++i){
				for(char j='a'; j<='z'; ++j){
					if(tempStr[i] == j){
						continue;
					}else{
						string replaceStr = tempStr;
						replaceStr[i] = j;
						if(dict.find(replaceStr)!=dict.end() || replaceStr == end){
							if(!pathMap[replaceStr] ||  pathMap[replaceStr] && pathMap[replaceStr] >= pathMap[tempStr]+1){
								if(replaceStr == end && pathMap[tempStr]+1 < 2){
									continue;
								}
								if(pathMap[replaceStr]  && pathMap[replaceStr] > pathMap[tempStr]+1){
									prevStrVec[replaceStr].clear();
								}else if(pathMap[replaceStr]  && pathMap[replaceStr] == pathMap[tempStr]+1){
								    prevStrVec[replaceStr].push_back(tempStr);
								    continue;
								}
								pathMap[replaceStr] = pathMap[tempStr]+1;
								strQue.push(replaceStr);
								prevStrVec[replaceStr].push_back(tempStr);
							}
						}
					}
				}
			}
		}
		if(pathMap[end]){
			vector<string> tempVec;
			tempVec.push_back(end);
			int shortLength = pathMap[end];
			findPaths(end,prevStrVec,tempVec,shortLength);
		}
		pathMap.clear();
		return paths;
	}
	void findPaths(string& end,unordered_map<string,vector<string>> &prevStrVec,vector<string> &path,int shortLength){
		vector<string> preEndVec = prevStrVec[end];
		if(preEndVec.empty()){
			paths.push_back(path);
			return;
		}
	    if(path.size()==shortLength){
	        return;
	    }
		for(int j=0; j<preEndVec.size(); ++j){
			string preStr = preEndVec[j];
			vector<string> tempPath = path;
			tempPath.push_back(preStr);
			findPaths(preStr,prevStrVec,tempPath,shortLength);
		}
	}
	vector<vector<string> > paths;
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值