笔试题62. LeetCode OJ (49)

笔试题62. LeetCode OJ (49)_第1张图片

         这个题目的意思是,给出一组单词,找出其中所有"异构"的单词组,异构的条件是单词的组成字符的种类和各字符出现的次数相同,上面图中的例子就可以说明这个问题,不过这个题也有一些要求:最后各个单词组必须有序,即按照单词大小排序。

     我看到这个题的时候,首先的思路是:使用 map<string,int> 结构,然后将每个单词排序----------异构的单词排序后一定相同,并以排序后的单词作为key值,然后循环去找和当前异构的单词。我的代码如下:

  

解法一,时间复杂度很可能不满足要求,
class Solution {
public:
	vector<vector<string>> groupAnagrams(vector<string>& strs)
	{
		/*
			满足题意的"单词"都是组成元素相同且出现次数相同但是位置不同而已;
			我们可以对字符串进行排序,然后就方便比较了;
			为了方便比较我们可以使用 map (<string,int>)来解决;
		*/
		vector<vector<string>> ret;
		ret.clear();
		map<string, int> M;
		size_t len = strs.size();
		int pos = 0; //用于统计当前的“单词”

		for (size_t i = 0; i < len; ++i)
		{ /* 该方法可能对某些项目重复计算,而导致时间复杂度太低*/
			vector<string> stmp;
			stmp.clear();
			string tmp = strs[i];			
			//排序
			sort(tmp.begin(), tmp.end());
			
			if (M.find(tmp) == M.end())
			{//没找到,说明是"新的一类"单词
				M.insert(pair<string, int>(tmp, ++pos));
				stmp.push_back(strs[i]);
			}
			else
			{//找到了说明该单词已经本统计过了,不再计算
				continue;
			}

			//从下一个位置依次去找"同一类的单词"
			for (size_t j = i + 1; j < len; ++j)
			{
				tmp = strs[j];
				sort(tmp.begin(), tmp.end());
				if (M.find(tmp) != M.end() && M[tmp] == pos)
				{
					stmp.push_back(strs[j]);
				}
				else
				{
					continue;
				}
			}

			// 将单词排序
			if (stmp.size() > 0)
			{
				sort(stmp.begin(), stmp.end());
				ret.push_back(stmp);
			}
		}

		return ret;
	}
};
但是运行的结构是无法通过由970个单词组成的 vector<string>,我将测试用例复制下来了,估计有100行左右吧,下面是我的截图,当时就感觉到了内心是崩溃的!

笔试题62. LeetCode OJ (49)_第2张图片

     程序运行提交的结果是超时,我自己也运行了一下,大概需要5~8秒钟,确实效率太低了,我仔细检查了一下,找到了原因:重复的次数太多了,我这种做法的重复次数太多了,导致程序的效率下降了,而且选择key值的方法也不是很优,要知道将一个单词排序的时间也挺多的。所以我不得不改写代码,改成了另外的写法(借鉴了一些网友的),新的代码如下:

class Solution 
{
public:   
	vector<vector<string>> groupAnagrams(vector<string>& strs) 
	{
	    /*
			满足题意的"单词"都是组成元素相同且出现次数相同但是位置不同而已;
			我们可以对字符串进行排序,然后就方便比较了;
			为了方便比较我们可以使用 map (<string,int>)来解决;
		*/
		map<vector<int>, vector<string> > m;
		map<vector<int>, vector<string> >::iterator it;        
		
		for (int i = 0; i < strs.size(); i++)        
		{ 
		    /*通过字符出现的位置以及次数来作为判断的标准*/
			vector<int> cnts(26, 0);            
			for (int j = 0; j < strs[i].size(); j++)            
			{ //统计各个字符出现的次数
				cnts[strs[i][j] - 'a']++; 
			}            
			it = m.find(cnts);  //找符合要求的数组

			if (it != m.end())
			{ //找到的话说明是“一类元素”,在后面追加
				it->second.push_back(strs[i]);
			}
			else
			{ // 没找到的话就是新的单词,新创建一个
				m.insert(pair<vector<int>, vector<string> >(cnts, vector<string>(strs.begin() + i, strs.begin() + i + 1)));
			}
		}

		vector<vector<string> > groups;  
		for (it = m.begin(); it != m.end(); it++)      
		{  //汇总
			sort(it->second.begin(), it->second.end());     
			groups.push_back(it->second);
		}        
		return groups; 
	} 
};
       新的方法是采用一个单词中各个字符出现的次数以及出现了哪些来作为key值的,当然主要还是使用map来解题的,这个算法只需要遍历一遍就可以完成90%的工作。思路是:

(1)按照一个单词中各字符出现的数目以及出现了哪些作为key值;

(2).然后在Map中寻找,该key值,若找到,则将该单词push_back到该key值的value中(value是vector<string>)

(3).若没找到以该key值新建一个项目

遍历完成后,所有的异构单词被分别分到相同的vector中去了,接着对这些单词进行排序,然后在放到 vector<vector<string>> 对象中即可。
结果如下:

笔试题62. LeetCode OJ (49)_第3张图片

你可能感兴趣的:(LeetCode,C++,算法,map)