当前位置: 首页 > news >正文

50-字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

解释:

  • 在 strs 中没有字符串可以通过重新排列来形成 "bat"
  • 字符串 "nat" 和 "tan" 是字母异位词,因为它们可以重新排列以形成彼此。
  • 字符串 "ate" ,"eat" 和 "tea" 是字母异位词,因为它们可以重新排列以形成彼此。

示例 2:

输入: strs = [""]

输出: [[""]]

示例 3:

输入: strs = ["a"]

输出: [["a"]]

提示:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

 

字母异位词分组的三种方法

要将字母异位词组合在一起,可以通过统计字符频率或排序字符的方式来识别它们。以下是三种不同的实现方法:

方法一:排序键哈希表法

将每个字符串排序后作为键,原字符串作为值存入哈希表,最后提取哈希表的值作为结果。

function groupAnagrams(strs: string[]): string[][] {const map = new Map<string, string[]>();for (const str of strs) {// 将字符串排序后作为键const sortedKey = str.split('').sort().join('');// 如果键不存在,初始化一个数组if (!map.has(sortedKey)) {map.set(sortedKey, []);}// 将原字符串添加到对应键的数组中map.get(sortedKey)!.push(str);}// 返回哈希表中的所有值return Array.from(map.values());
}

方法二:字符频率哈希表法

统计每个字符串中字符的频率,将频率数组转换为字符串作为键,存入哈希表。

function groupAnagrams(strs: string[]): string[][] {const map = new Map<string, string[]>();for (const str of strs) {// 统计字符频率的数组(26个小写字母)const count = new Array(26).fill(0);// 统计每个字符的出现次数for (const char of str) {count[char.charCodeAt(0) - 'a'.charCodeAt(0)]++;}// 将频率数组转换为字符串作为键const key = count.join('#');// 如果键不存在,初始化一个数组if (!map.has(key)) {map.set(key, []);}// 将原字符串添加到对应键的数组中map.get(key)!.push(str);}// 返回哈希表中的所有值return Array.from(map.values());
}
方法三:质数乘积法(理论优化,但实际可能溢出)

将每个字符映射为一个质数,通过计算字符串中所有字符对应的质数乘积作为键,确保字母异位词的乘积相同。

function groupAnagrams(strs: string[]): string[][] {// 26个小写字母对应的质数const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29,31, 37, 41, 43, 47, 53, 59, 61, 67,71, 73, 79, 83, 89, 97, 101];const map = new Map<number, string[]>();for (const str of strs) {// 计算质数乘积作为键let product = 1;for (const char of str) {const index = char.charCodeAt(0) - 'a'.charCodeAt(0);product *= primes[index];}// 如果键不存在,初始化一个数组if (!map.has(product)) {map.set(product, []);}// 将原字符串添加到对应键的数组中map.get(product)!.push(str);}// 返回哈希表中的所有值return Array.from(map.values());
}

复杂度分析

方法时间复杂度空间复杂度说明
方法一(排序键)O(n * k log k)O(n * k)n 是字符串数量,k 是最大字符串长度,排序操作主导时间复杂度
方法二(频率统计)O(n * k)O(n * k)直接统计字符频率,时间复杂度更优,适用于字符集较小的情况
方法三(质数乘积)O(n * k)O(n * k)理论上时间复杂度最优,但可能存在整数溢出问题,仅适用于字符串较短的情况

测试示例

// 示例1测试
console.log(groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]));
// 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]// 示例2测试
console.log(groupAnagrams([""]));
// 输出: [[""]]// 示例3测试
console.log(groupAnagrams(["a"]));
// 输出: [["a"]]// 自定义测试
console.log(groupAnagrams(["listen", "silent", "enlist"]));
// 输出: [["listen","silent","enlist"]]

方法选择建议

  • 方法一实现简单,适用于各种字符集,但时间复杂度较高,适合字符串长度较小的情况。
  • 方法二是最优解,时间复杂度最低,尤其适合字符集较小的场景(如本题中的小写字母)。
  • 方法三理论上时间复杂度最优,但存在整数溢出风险,实际应用中需谨慎使用。

在实际应用中,推荐使用方法二作为首选解决方案,它在效率和实现复杂度之间取得了良好平衡。

方法一的时间复杂度和空间复杂度是多少?

除了排序键哈希表法,还有其他方法可以实现字母异位词分组吗?

方法二中的计数数组法是如何工作的?

http://www.dtcms.com/a/291466.html

相关文章:

  • SmartETL循环流程的设计与应用
  • 外辐射源入门综述
  • 板凳-------Mysql cookbook学习 (十二--------4)
  • c++找工作(qt)
  • 【金仓数据库产品体验官】_KingbaseES(SQLServer兼容版)保姆级安装教程
  • LiteCoT:难度感知的推理链压缩与高效蒸馏框架
  • 【CNN】卷积神经网络多通道卷积与偏置过程- part2
  • AI Red Teaming 分析
  • 鸿蒙开发中与 AI 编码助手的共处之道(ArkTS 视角)
  • sky-take-out项目中Redis的使用
  • 【每日算法】专题十七_多源 BFS
  • Java 实现 UDP 多发多收通信
  • 图论(2):最短路
  • http协议学习-body各种类型
  • cs336 Lecture2
  • SQL基础入门② | 运算符篇
  • 【HarmonyOS】ArkTS语法详细解析
  • 阿里云技术三面:java社招面经+面试题分享!
  • rancher使用rke在华为云多网卡的服务器上安装k8s集群问题处理
  • Supervisor 核心原理:如何实现进程管理?
  • 机器视觉的食品包装贴标应用
  • [论文阅读] 人工智能 | ZipMPC:让短视的MPC拥有长远眼光——通过模仿学习压缩长 horizon 智慧
  • A1-静态Mpls
  • 二、计算机网络技术——第2章:物理层
  • [1-01-01].第90节:如何学习新特性:
  • 一文速通《矩阵的特征值和特征向量》
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘pywifi’问题
  • 马斯克布局儿童 AI 领域,xAI 推出 Baby Grok,将带来哪些变革?
  • Windows防火墙配置详解
  • PDF限制功能如何用?简单教程来了!