题目:
给你一个下标从 0 开始的字符串数组 words 。
如果两个字符串由相同的字符组成,则认为这两个字符串 相似 。
- 例如,
"abca"和"cba"相似,因为它们都由字符'a'、'b'、'c'组成。 - 然而,
"abacba"和"bcfd"不相似,因为它们不是相同字符组成的。
请你找出满足字符串 words[i] 和 words[j] 相似的下标对 (i, j) ,并返回下标对的数目,其中 0 <= i < j <= words.length - 1 。
示例 1:
输入:words = ["aba","aabb","abcd","bac","aabc"] 输出:2 解释:共有 2 对满足条件: - i = 0 且 j = 1 :words[0] 和 words[1] 只由字符 'a' 和 'b' 组成。 - i = 3 且 j = 4 :words[3] 和 words[4] 只由字符 'a'、'b' 和 'c' 。
示例 2:
输入:words = ["aabb","ab","ba"] 输出:3 解释:共有 3 对满足条件: - i = 0 且 j = 1 :words[0] 和 words[1] 只由字符 'a' 和 'b' 组成。 - i = 0 且 j = 2 :words[0] 和 words[2] 只由字符 'a' 和 'b' 组成。 - i = 1 且 j = 2 :words[1] 和 words[2] 只由字符 'a' 和 'b' 组成。
示例 3:
输入:words = ["nba","cba","dba"] 输出:0 解释:不存在满足条件的下标对,返回 0 。
提示:
1 <= words.length <= 1001 <= words[i].length <= 100words[i]仅由小写英文字母组成
解法:
解决思路
-
提取字符集合:
-
对于每个字符串,提取其中包含的字符种类(去重)。
-
例如,
"aba"的字符集合是{'a', 'b'},"aabb"的字符集合也是{'a', 'b'}。
-
-
比较字符集合:
-
如果两个字符串的字符集合相同,则它们相似。
-
例如,
"aba"和"aabb"的字符集合都是{'a', 'b'},因此它们相似。
-
-
统计相似对数:
-
对于所有字符串,统计具有相同字符集合的字符串数量。
-
如果有
k个字符串具有相同的字符集合,则这些字符串之间可以形成C(k, 2)对相似对(即从k个字符串中选 2 个的组合数)。
-
实现步骤
-
提取字符集合:
-
对每个字符串,将其字符去重并排序,生成一个唯一的标识符(例如,将字符集合转换为字符串)。
-
例如,
"aba"的字符集合是{'a', 'b'},可以转换为字符串"ab"。
-
-
统计字符集合的出现次数:
-
使用哈希表(
unordered_map)记录每个字符集合的出现次数。 -
例如,
"ab"出现 2 次,"abc"出现 1 次。
-
-
计算相似对数:
-
对于哈希表中的每个字符集合,如果有
k个字符串具有相同的字符集合,则这些字符串之间可以形成k * (k - 1) / 2对相似对。 -
将所有字符集合的相似对数累加,得到最终结果。
-
代码实现
class Solution {
public:int similarPairs(vector<string>& words) {unordered_map<string, int> countMap;// 遍历每个字符串,提取字符集合并统计for (const string& word : words) {string charSet = getCharSet(word);countMap[charSet]++;}int result = 0;// 计算满足条件的下标对数量for (const auto& pair : countMap) {int k = pair.second;if (k >= 2) {result += k * (k - 1) / 2;}}return result;}private:string getCharSet(const string& word) {vector<char> chars(word.begin(), word.end());sort(chars.begin(), chars.end());chars.erase(unique(chars.begin(), chars.end()), chars.end());return string(chars.begin(), chars.end());}
};
代码详细解释
-
getCharSet函数:-
输入:一个字符串
word。 -
输出:该字符串的字符集合(去重并排序后的字符串)。
-
实现步骤:
-
将字符串转换为字符数组
chars。 -
对字符数组排序(
sort)。 -
去重(
unique和erase)。 -
将字符数组转换为字符串并返回。
-
示例:
-
输入:
"aba" -
输出:
"ab"
-
-
similarPairs函数:-
输入:字符串数组
words。 -
输出:满足条件的下标对数量。
-
实现步骤:
-
遍历每个字符串,调用
getCharSet获取字符集合。 -
使用哈希表
countMap统计每个字符集合的出现次数。 -
遍历哈希表,计算每个字符集合的相似对数,并累加到结果中。
-
示例:
-
输入:
["aba", "aabb", "abcd", "bac", "aabc"] -
哈希表内容:
{"ab": 2, "abcd": 1, "abc": 2} -
计算结果:
C(2, 2) + C(2, 2) = 1 + 1 = 2
-
复杂度分析
-
时间复杂度:
-
提取字符集合:对于每个字符串,排序和去重的复杂度为
O(m log m),其中m是字符串的平均长度。 -
统计哈希表:遍历所有字符串的复杂度为
O(n),其中n是字符串的数量。 -
计算相似对数:遍历哈希表的复杂度为
O(n)。 -
总时间复杂度:
O(n * m log m)。
-
-
空间复杂度:
-
哈希表
countMap的空间复杂度为O(n)。 -
字符集合的空间复杂度为
O(m)。 -
总空间复杂度:
O(n * m)。
-
示例运行
示例 1:
输入:words = ["aba", "aabb", "abcd", "bac", "aabc"]
-
提取字符集合:
-
"aba"->"ab" -
"aabb"->"ab" -
"abcd"->"abcd" -
"bac"->"abc" -
"aabc"->"abc"
-
-
统计哈希表:
-
{"ab": 2, "abcd": 1, "abc": 2}
-
-
计算相似对数:
-
"ab"出现 2 次 ->C(2, 2) = 1 -
"abc"出现 2 次 ->C(2, 2) = 1 -
总相似对数:
1 + 1 = 2
-
输出:2
示例 2:
输入:words = ["aabb", "ab", "ba"]
-
提取字符集合:
-
"aabb"->"ab" -
"ab"->"ab" -
"ba"->"ab"
-
-
统计哈希表:
-
{"ab": 3}
-
-
计算相似对数:
-
"ab"出现 3 次 ->C(3, 2) = 3 -
总相似对数:
3
-
输出:3
示例 3:
输入:words = ["nba", "cba", "dba"]
-
提取字符集合:
-
"nba"->"abn" -
"cba"->"abc" -
"dba"->"abd"
-
-
统计哈希表:
-
{"abn": 1, "abc": 1, "abd": 1}
-
-
计算相似对数:
-
每个字符集合只出现 1 次,无法形成相似对。
-
总相似对数:
0
-
输出:0
总结
通过提取字符集合、统计哈希表,并计算组合数,我们可以高效地解决这个问题。代码的时间复杂度和空间复杂度都在合理范围内,能够处理题目中的最大输入规模。