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

news2025/2/23 19:18:46

题目:

给你一个下标从 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.coloradmin.cn/o/2304048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安科瑞能源物联网平台助力企业实现绿色低碳转型

安科瑞顾强 随着全球能源结构的转型和“双碳”目标的推进&#xff0c;能源管理正朝着智能化、数字化的方向快速发展。安科瑞电气股份有限公司推出的微电网智慧能源管理平台&#xff08;EMS 3.0&#xff09;&#xff0c;正是这一趋势下的创新解决方案。该平台集成了物联网&…

Spring Boot 中使用 @Transactional 注解配置事务管理

事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。编程式事务指的是通过编码方式实现事务&#xff1b;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污…

动态链接器(九):.init和.init_array

ELF文件中的.init和.init_array段是程序初始化阶段的重要组成部分&#xff0c;用于在main函数执行前完成必要的初始化操作。 1 .init段和.init_array 段 1.1 作用 .init段包含编译器生成的初始化代码&#xff0c;通常由运行时环境&#xff08;如C标准库的启动例程&#xff0…

RT-Thread+STM32L475VET6——TF 卡文件系统

文章目录 前言一、板载资源二、具体步骤1.打开CubeMX进行USB配置1.1 使用外部高速时钟&#xff0c;并修改时钟树1.2 打开SPI1&#xff0c;参数默认即可(SPI根据自己需求调整&#xff09;1.3 打开串口&#xff0c;参数默认1.4 生成工程 2.配置SPI2.1 打开SPI驱动2.2 声明使用SPI…

[论文解析]OmniRe: Omni Urban Scene Reconstruction

OmniRe: Omni Urban Scene Reconstruction 论文地址&#xff1a;https://arxiv.org/abs/2408.16760 代码地址&#xff1a;https://github.com/ziyc/drivestudio 项目地址&#xff1a;https://ziyc.github.io/omnire/ 论文解读 总结 这篇论文代表了一种重建的方向&#xff0…

【微服务优化】ELK日志聚合与查询性能提升实战指南

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

Docker实战-使用docker compose搭建博客

docker run 部署 创建blog网络 [rootk8s-master ~]# docker network create blog 8f533a5a1ec65eae3f98c0ae5a76014a3ab1bf3c087ad952cdc100cc7a658948 [rootk8s-master ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 8f533a5a1ec6 blog bridge …

【JT/T 808协议】808 协议开发笔记 ② ( 终端注册 | 终端注册应答 | 字符编码转换网站 )

文章目录 一、消息头 数据1、消息头拼接2、消息 ID 字段3、消息体属性 字段4、终端手机号 字段5、终端流水号 字段 二、消息体 数据三、校验码计算四、最终计算结果五、终端注册应答1、分解终端应答数据2、终端应答 消息体 数据 六、字符编码转换网站 一、消息头 数据 1、消息头…

51单片机学习之旅——定时器

打开软件 1与其它等于其它&#xff0c;0与其它等于0 1或其它等于1&#xff0c;0或其它等于其它 TMODTMOD&0xF0;//0xF01111 0000进行与操作&#xff0c;高四位保持&#xff0c;低四位清零&#xff0c;高四位定时器1&#xff0c;低四位定时器0 TMODTMOD|0x01;//0x010000 0…

hot100_139. 单词拆分

hot100_139. 单词拆分 思路 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a; 输入:…

SQLMesh 系列教程7- 详解 seed 模型

SQLMesh 是一个强大的数据建模和管道管理工具&#xff0c;允许用户通过 SQL 语句定义数据模型并进行版本控制。Seed 模型是 SQLMesh 中的一种特殊模型&#xff0c;主要用于初始化和填充基础数据集。它通常包含静态数据&#xff0c;如参考数据和配置数据&#xff0c;旨在为后续的…

windows11那些事

一.windows11简介 Windows11是‌微软公司于2021年发布的桌面端操作系统&#xff0c;它带来了许多新的功能和改进&#xff0c;旨在提升用户体验和工作效率。以下是一些关于Windows 11的基础知识和使用技巧&#xff1a; ‌‌通用搜索&#xff1a;通过任务栏上的搜索或按Windows…

VividTalk:南京大学、阿里巴巴等机构联合研发的开源3D说话人生成框架

目录 一、前言二、项目概述三、技术架构四、优势特点五、性能评估六、应用场景七、结论与展望 一、前言 在当今人工智能飞速发展的时代&#xff0c;人机交互的方式正不断创新和优化。VividTalk作为南京大学、阿里巴巴、字节跳动和南开大学联合开发的一项开创性技术&#xff0c…

pyside6学习专栏(三):自定义QLabel标签扩展类QLabelEx

标签是界面设计中最常用的控件&#xff0c;本文演示了如何基于PySide6的QLabex控件类扩展定义QLabelEX类&#xff0c;以实现更少的编码完成各种图像、彩色文本、动画的加载和显示&#xff0c;丰富界面显示 本示例演示了QLabel和其扩展类QLabelEx分别显示文本、图像、动画的使用…

后“智驾平权”时代,谁为安全冗余和体验升级“买单”

线控底盘&#xff0c;正在成为新势力争夺下一个技术普及红利的新赛点。 尤其是进入2025年&#xff0c;比亚迪、长安等一线传统自主品牌率先开启高阶智驾的普及战&#xff0c;加上此前已经普及的智能座舱&#xff0c;舱驾智能的「科技平权」进一步加速行业启动「线控底盘」上车窗…

springboot408-基于Java的樱洵宾馆住宿管理系统(源码+数据库+纯前后端分离+部署讲解等)

&#x1f495;&#x1f495;作者&#xff1a; 爱笑学姐 &#x1f495;&#x1f495;个人简介&#xff1a;十年Java&#xff0c;Python美女程序员一枚&#xff0c;精通计算机专业前后端各类框架。 &#x1f495;&#x1f495;各类成品Java毕设 。javaweb&#xff0c;ssm&#xf…

EasyRTC:基于WebRTC与P2P技术,开启智能硬件音视频交互的全新时代

在数字化浪潮的席卷下&#xff0c;智能硬件已成为我们日常生活的重要组成部分&#xff0c;从智能家居到智能穿戴&#xff0c;从工业物联网到远程协作&#xff0c;设备间的互联互通已成为不可或缺的趋势。然而&#xff0c;高效、低延迟且稳定的音视频交互一直是智能硬件领域亟待…

鸿蒙NEXT应用App测试-通用测试

注意&#xff1a;大家记得学完通用测试记得再学鸿蒙专项测试 https://blog.csdn.net/weixin_51166786/article/details/145768653 注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章…

transfmer学习认识

整体架构 1.自注意机制 1.1.softmax 在机器学习和深度学习中&#xff0c;softmax 函数是一个常用的激活函数&#xff0c;用于将一个向量转换为一个概率分布。softmax 函数的公式如下&#xff1a; ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/35c158988402498ba6…

人工智能(AI)的不同维度分类

人工智能(AI)的分类 对机器学习进行分类的方式多种多样&#xff0c;可以根据算法的特性、学习方式、任务类型等不同维度进行分类这些分类都不是互斥的&#xff1a; 1、按数据模态不同:图像&#xff0c;文本&#xff0c;语音&#xff0c;多态等 2、按目标函数不同:判别式模型…