Anagrams

Anagrams

Given an array of strings, return all groups of strings that are anagrams.

Note: All inputs will be in lower-case.

什么是anagrams?

/** 整理的提交代码
 * 处理复杂度为O(n),n是字符串个数,但是其中有排序等步骤没有固定考虑
 * 主要思路:
 * 1、先对特殊情况进行处理
 * 2、为了输出原始字符串,记录原始字符串和经过排序的字符串,并将这个对组(pair)存入一个vector中,
 *    也可以将其存入一个map中,我是为了后面对字符串对组排序后再进行查找时的效率,vector是顺序存储的。
 *    但无论是用vector还是map都会另外申请一块二倍于原来字符串数组大小的空间,比较浪费空间。
 * 3、接下来排序这个对组vector,排序准则是对组的第二个元素(字符串)小与关系,这个排序过程比较耗费时间。
 * 4、使用两个索引变量,每次固定第一个然后移动第二个,如果不是Anagrams关系,则判断两个索引之间的距离,
 *    如果大于两个则取出对应对组的第一个元素(原始字符串)。如果到了末尾且相等则也要判断两个索引距离。
 *    总之这个过程是O(n)复杂度,它只遍历一遍之前创建的对组vector,没有重复或者说回溯。
 * 提交结果: 
 * (Judge Small) 
 * Run Status: Accepted! 
 * Program Runtime: 4 milli secs (基本在几毫秒)
 * Progress: 12/12 test cases passed. 
 * (Judge Large) 
 * Run Status: Accepted!
 * Program Runtime: 208 milli secs	(基本稳定在二百零几毫秒左右)
 * Progress: 95/95 test cases passed.
 */
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

class Solution {
private:
	static bool pairSortCriterion(const pair<string, string>& p1, const pair<string, string>& p2)
	{
		return p1.second < p2.second;
	}
public:
	vector<string> anagrams(vector<string> &strs) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		size_t size = strs.size();
		vector<string> result;
		// 特殊情况处理
		if (size < 2)
		{
			return result;
		}
		pair<string, string> word_pair;	// <原始字符串,排序后字符串>
		vector<pair<string, string> > pairs;
		// 所有字符串排序
		for (size_t i = 0; i != size; i++)
		{
			word_pair.first = strs[i];
			sort(strs[i].begin(), strs[i].end());
			word_pair.second = strs[i];
			pairs.push_back(word_pair);
		}
		// 字符串pair数组排序
		sort(pairs.begin(), pairs.end(), pairSortCriterion);	// string本省支持<。

		size_t i = 0, j = 0;
		size_t k = i;
		int count = 1;
		while (j < size-1)
		{
			j++;
			if (pairs[i].second == pairs[j].second && j == size-1)
			{
				for (k = i; k <= j; k++)
				{
					result.push_back(pairs[k].first);
				}
			}
			// 判断i-j范围内的字符串
			if (pairs[i].second == pairs[j].second)
			{
				count++;
			}
			else
			{
				if (count > 1)
				{
					// 保存i-j范围内的字符串
					for (k = i; k < j; k++)
					{
						result.push_back(pairs[k].first);
					}
				}
				i = j;	// 跳到下一个考察元素,即当前位置j处的字符串,之前的i-j范围内的是符合要求的字符串
				count = 1;
			}			
		}

		return result;
	}
};

int main()
{
	vector<string> strs;
	string str;
	cout << "input strs: " << endl;
	while (cin >> str)
	{
		strs.push_back(str);
	}

	Solution s;
	vector<string> result = s.anagrams(strs);

	cout << "result: " << endl;
	for (size_t i = 0; i != result.size(); i++)
	{
		cout << result[i] << endl;
	}

	return 0;
}

自定义的排序准则作为全局函数或者类静态成员函数也需要放入测试系统。不可以将其放入类中作为一个普通成员函数,因为有this参数。
### 关于 `Group Anagrams` 的实现方法 #### 方法一:基于排序的哈希表 对于每一个字符串,先将其字符按照字典顺序排列得到一个新的字符串作为键值存入哈希表中。由于字母异位词经过这样的处理后会产生相同的键值,因此可以将具有相同键值的所有原始字符串收集起来形成最终的结果集[^1]。 ```cpp vector<vector<string>> groupAnagrams(vector<string>& strs) { unordered_map<string, vector<string>> mp; for (string& str : strs) { string key = str; sort(key.begin(), key.end()); mp[key].push_back(str); } vector<vector<string>> ans; for (auto it = mp.begin(); it != mp.end(); ++it) { ans.push_back(it->second); } return ans; } ``` 这种方法的时间复杂度主要取决于排序操作以及遍历输入列表的操作。如果n表示输入列表长度,k代表最长单词长度,则时间复杂度大约为O(n * k log k)。 #### 方法二:基于计数数组的哈希表 考虑到ASCII码范围内的字符数量有限(共26个小写字母),可以直接利用固定大小(26)的整型数组记录每个字符串内各个字符出现次数的情况,并以此构建唯一的key用于存储到hashmap当中去。这种方式避免了显式的字符串排序过程,在某些情况下可能会更高效一些。 ```cpp vector<vector<string>> groupAnagrams(vector<string>& strs) { unordered_map<string, vector<string>> mp; for (const auto& s : strs){ array<int, 26> counts{}; for(const char c:s){ counts[c-'a']++; } // 将counts转换成可作为key使用的字符串形式 string key = ""; for(auto count:counts){ key += "#"+to_string(count); } mp[key].emplace_back(s); } vector<vector<string>> res; for(auto& p:mp){ res.emplace_back(p.second); } return res; } ``` 此版本通过使用定长的频率分布向量代替直接对字符串进行排序的方式减少了不必要的计算开销,理论上能够提供更好的性能表现。 #### 方法三:质数相乘法 另一种巧妙的做法是给每个不同的字母分配一个独一无二的小质数值,之后把整个字符串看作是由这些质因数构成的大合数;这样只要两个串对应的积相等就说明它们互为变位词。不过这种思路虽然新颖有趣但在实际应用时效率未必占优,因为涉及到大数运算等问题。 ```cpp // 这里仅给出概念性的伪代码示意而非完整的解决方案 unordered_map<long long,vector<string>> map; for each word w do{ product=1; foreach character ch in w do{ product *= primes[ch]; //假设primes[]已经预先定义好并初始化完毕 } map[product].add(w); } return convert(map.values()); // 把map里的value部分转成题目要求的形式返回 ``` 上述三种方式各有特点,可以根据具体场景和个人偏好选择合适的一种来解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值