题目:
给你一个下标从 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 <= 100
1 <= words[i].length <= 100
words[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
对相似对。 -
将所有字符集合的相似对数累加,得到最终结果。
-
代码实现
cpp
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
总结
通过提取字符集合、统计哈希表,并计算组合数,我们可以高效地解决这个问题。代码的时间复杂度和空间复杂度都在合理范围内,能够处理题目中的最大输入规模。