LeetCode 49. 字母异位词分组

LeetCode 49. 字母异位词分组

题目描述

相关标签:哈希表、字符串、排序

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例

示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]

示例 2:
输入: strs = [""]
输出: [[""]]

示例 3:
输入: strs = ["a"]
输出: [["a"]]

提示

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

解题思路

字母异位词的核心特征是:每个字符串中包含的字母种类和数量完全相同,只是顺序可能不同。因此,我们需要找到一种方法来标识一组字母异位词。常见方法包括:

  1. 排序法:将每个字符串的字符排序后作为键(key),相同的键对应一组字母异位词。
  2. 计数法:统计每个字符串中每个字母出现的次数,形成一个特征值作为键来分组。
  3. 质数乘积法:为每个字母分配一个唯一的质数,计算字符串中所有字母对应质数的乘积,作为键来分组。

以下我们重点分析基于 排序法 的解法,并提供代码实现。


代码实现(排序法)

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        map = {}
        for s in strs:
            key = ''.join(sorted(s))  # 对字符串排序作为键
            if key not in map:
                map[key] = []
            map[key].append(s)
        return list(map.values())  # 直接返回字典的值列表

代码解析

  1. 初始化字典:使用 map 字典来存储分组结果,键是排序后的字符串,值是对应的字母异位词列表。
  2. 遍历字符串数组:对输入数组 strs 中的每个字符串 s 进行处理。
  3. 生成键:将字符串 s 的字符排序后拼接成一个新字符串 key,确保字母异位词有相同的键。例如,"eat""tea" 排序后都变为 "aet"
  4. 分组:如果 key 不在字典中,初始化一个空列表;然后将当前字符串 s 添加到对应键的列表中。
  5. 返回结果:最后返回字典中所有值的列表,即分组后的结果。

复杂度分析

  • 时间复杂度O(n * k * log k)
    • n 是字符串数组 strs 的长度。
    • k 是单个字符串的最大长度,排序一个长度为 k 的字符串需要 O(k * log k) 的时间。
    • 总时间复杂度为遍历 n 个字符串,每个字符串排序所需时间之和。
  • 空间复杂度O(n)
    • 用于存储分组结果的字典 map 需要 O(n) 的空间,具体取决于输入字符串的数量和分组情况。

优点与缺点

  • 优点:逻辑简单,易于理解和实现;适用于大多数场景。
  • 缺点:排序操作 O(k * log k) 存在优化空间,尤其当字符串较长时,性能可能不如计数法。

替代解法对比

1. 计数法

思路:统计每个字符串中每个字母的出现次数,形成一个特征值作为键,避免排序操作。
代码

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        map = {}
        for s in strs:
            count = [0] * 26  # 统计每个字母的出现次数
            for char in s:
                count[ord(char) - ord('a')] += 1
            key = str(count)  # 将计数数组转为字符串作为键
            if key not in map:
                map[key] = []
            map[key].append(s)
        return list(map.values())
  • 时间复杂度O(n * k),计数操作是线性时间。
  • 空间复杂度O(n)
  • 优点:比排序法更快,尤其在字符串较长时。

2. 质数乘积法

思路:为每个字母分配一个唯一质数,计算字符串中字母对应质数的乘积作为键。
代码

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        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]
        map = {}
        for s in strs:
            product = 1
            for char in s:
                product *= primes[ord(char) - ord('a')]
            if product not in map:
                map[product] = []
            map[product].append(s)
        return list(map.values())
  • 时间复杂度O(n * k)
  • 空间复杂度O(n)
  • 缺点:可能存在整数溢出问题(Python 中无此问题),可读性稍差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值