力扣LeetCode: 2506 统计相似字符串对的数目

news/2025/2/23 18:03:30

题目:

给你一个下标从 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] 仅由小写英文字母组成

解法:

解决思路

  1. 提取字符集合

    • 对于每个字符串,提取其中包含的字符种类(去重)。

    • 例如,"aba" 的字符集合是 {'a', 'b'}"aabb" 的字符集合也是 {'a', 'b'}

  2. 比较字符集合

    • 如果两个字符串的字符集合相同,则它们相似。

    • 例如,"aba" 和 "aabb" 的字符集合都是 {'a', 'b'},因此它们相似。

  3. 统计相似对数

    • 对于所有字符串,统计具有相同字符集合的字符串数量。

    • 如果有 k 个字符串具有相同的字符集合,则这些字符串之间可以形成 C(k, 2) 对相似对(即从 k 个字符串中选 2 个的组合数)。


实现步骤

  1. 提取字符集合

    • 对每个字符串,将其字符去重并排序,生成一个唯一的标识符(例如,将字符集合转换为字符串)。

    • 例如,"aba" 的字符集合是 {'a', 'b'},可以转换为字符串 "ab"

  2. 统计字符集合的出现次数

    • 使用哈希表(unordered_map)记录每个字符集合的出现次数。

    • 例如,"ab" 出现 2 次,"abc" 出现 1 次。

  3. 计算相似对数

    • 对于哈希表中的每个字符集合,如果有 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());
    }
};

代码详细解释

  1. getCharSet 函数

    • 输入:一个字符串 word

    • 输出:该字符串的字符集合(去重并排序后的字符串)。

    • 实现步骤:

      • 将字符串转换为字符数组 chars

      • 对字符数组排序(sort)。

      • 去重(unique 和 erase)。

      • 将字符数组转换为字符串并返回。

    示例

    • 输入:"aba"

    • 输出:"ab"

  2. similarPairs 函数

    • 输入:字符串数组 words

    • 输出:满足条件的下标对数量。

    • 实现步骤:

      • 遍历每个字符串,调用 getCharSet 获取字符集合。

      • 使用哈希表 countMap 统计每个字符集合的出现次数。

      • 遍历哈希表,计算每个字符集合的相似对数,并累加到结果中。

    示例

    • 输入:["aba", "aabb", "abcd", "bac", "aabc"]

    • 哈希表内容:{"ab": 2, "abcd": 1, "abc": 2}

    • 计算结果:C(2, 2) + C(2, 2) = 1 + 1 = 2


复杂度分析

  1. 时间复杂度

    • 提取字符集合:对于每个字符串,排序和去重的复杂度为 O(m log m),其中 m 是字符串的平均长度。

    • 统计哈希表:遍历所有字符串的复杂度为 O(n),其中 n 是字符串的数量。

    • 计算相似对数:遍历哈希表的复杂度为 O(n)

    • 总时间复杂度:O(n * m log m)

  2. 空间复杂度

    • 哈希表 countMap 的空间复杂度为 O(n)

    • 字符集合的空间复杂度为 O(m)

    • 总空间复杂度:O(n * m)


示例运行

示例 1:

输入:words = ["aba", "aabb", "abcd", "bac", "aabc"]

  1. 提取字符集合:

    • "aba" -> "ab"

    • "aabb" -> "ab"

    • "abcd" -> "abcd"

    • "bac" -> "abc"

    • "aabc" -> "abc"

  2. 统计哈希表:

    • {"ab": 2, "abcd": 1, "abc": 2}

  3. 计算相似对数:

    • "ab" 出现 2 次 -> C(2, 2) = 1

    • "abc" 出现 2 次 -> C(2, 2) = 1

    • 总相似对数:1 + 1 = 2

输出:2


示例 2:

输入:words = ["aabb", "ab", "ba"]

  1. 提取字符集合:

    • "aabb" -> "ab"

    • "ab" -> "ab"

    • "ba" -> "ab"

  2. 统计哈希表:

    • {"ab": 3}

  3. 计算相似对数:

    • "ab" 出现 3 次 -> C(3, 2) = 3

    • 总相似对数:3

输出:3


示例 3:

输入:words = ["nba", "cba", "dba"]

  1. 提取字符集合:

    • "nba" -> "abn"

    • "cba" -> "abc"

    • "dba" -> "abd"

  2. 统计哈希表:

    • {"abn": 1, "abc": 1, "abd": 1}

  3. 计算相似对数:

    • 每个字符集合只出现 1 次,无法形成相似对。

    • 总相似对数:0

输出:0


总结

通过提取字符集合、统计哈希表,并计算组合数,我们可以高效地解决这个问题。代码的时间复杂度和空间复杂度都在合理范围内,能够处理题目中的最大输入规模。


http://www.niftyadmin.cn/n/5863649.html

相关文章

计算机网络面试知识点总结

目录 1. 计算机网络的基本知识点2. OSI 七层模型3. TCP/IP 四层模型4. TCP 和 UDP4.1 TCP 协议4.2 TCP 流量控制4.3 TCP 拥塞控制4.4 TCP 三次握手4.5 TCP 四次挥手4.6 TCP 粘包问题4.7 TCP Socket交互流程4.8 UDP 协议以及和 TCP 协议的不同 5. HTTP协议5.1 HTTP 请求方法以及…

力扣-贪心-53 最大子数组和

思路 先把每一个值都加到当前集合中&#xff0c;记录当前的和&#xff0c;直到当前记录和小于0了&#xff0c;再重置改记录&#xff0c;再次尝试累加 代码 class Solution { public:int maxSubArray(vector<int>& nums) {int res INT32_MIN;int curSum 0;for(in…

ES6 新特性,优势和用法?

ES6 新特性&#xff0c;优势和用法&#xff1f; ES6&#xff08;ECMAScript 2015&#xff09;引入了许多新特性&#xff0c;这些特性让 JavaScript 变得更加强大、简洁和易于使用。下面为你详细介绍一些常见的 ES6 新特性、它们的优势以及用法。 1. 块级作用域&#xff1a;le…

零基础学QT、C++(六)制作桌面摄像头软件

目录 一、前言 二、Python项目包 三、C项目包 四、 项目说明 五、结语 章节汇总 一、前言 上一节&#xff0c;成功导入了OpenCV库 零基础学QT、C&#xff08;四&#xff09;QT程序打包-CSDN博客文章浏览阅读1.1k次&#xff0c;点赞29次&#xff0c;收藏23次。QT程序打包。将项…

【Gin-Web】Bluebell社区项目梳理4:帖子相关接口开发及实现

本文目录 一、创建帖子RoutersControllerLogic/serviceDao 二、查询帖子接口三、分页查询展示 一、创建帖子 Routers 创建帖子的接口需要经过JWT认证才能访问&#xff0c;相关JWT内容在昨天的博客中已经回顾过了。接下来继续往下看。 Controller Controller层的代码如下&…

C语言实现的常见算法示例

下面是一个使用C语言实现的几个常见算法示例&#xff0c;包括排序算法&#xff08;冒泡排序、快速排序&#xff09;、查找算法&#xff08;二分查找&#xff09;以及递归算法&#xff08;斐波那契数列&#xff09;。 1. 冒泡排序&#xff08;Bubble Sort&#xff09; #includ…

Flutter_学习记录_各个屏幕的适配

用flutter的这个库&#xff0c;可以解决&#xff1a;https://pub.dev/packages/flutter_screenutil 使用方法&#xff1a; 在pubspec.yaml文件中&#xff0c;添加库&#xff0c;如下图&#xff1a; 在main.dart中导入头文件 import package:flutter_screenutil/flutter_scre…

碳基生物的悲歌-DeepSeek思考实现Linux动态库递归收集工具

这是碳基生命的悲歌&#xff0c;还是地球文明的拐点&#xff1f; 今天因为复杂的Linux so 依赖问题&#xff0c;想写一个递归ldd收集所有依赖的工具。抱着试试看的态度&#xff0c;问了DeepSeek&#xff0c;经过5分钟的思考&#xff0c;给出的脚本一次运行通过&#xff0c;我的…