49_字母异位词分组(算法思路,优化和复杂度分析)

74 阅读3分钟

题目描述

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

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

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

示例 2:

输入: strs = [""]
输出: [[""]]

思路

对于相同的异位词分组,他们的元素都是相同的,只是元素排列顺序不同

那么可以通过创建一个映射,键为按字符编码顺序排列后的异位词,值为一个数组,存储具有相同元素的异位词

思路优化

可以通过一个字符数组来存储异位词的每个字母,通过这种方式也可以将字母排列不同的异位词进行分组

同时,可以省去排序过程的时间开销

复杂度分析

时间复杂度

  • 假设
    • N:输入数组 strs 的长度,即字符串的数量。
    • K:每个字符串的平均长度。
  • 主要操作分析
    1. 遍历字符串数组
      • 使用 strs.forEach 遍历所有字符串,时间复杂度为 O(N)。
    2. 字符串分组
      1. 使用排序分组的复杂度
        1. 对每个字符串 item 进行 split(''),生成字符数组,时间复杂度为 O(K)。
        2. 对字符数组进行 sort,时间复杂度为 O(K log K)。
        3. 使用 join('') 将排序后的字符数组重新组合成字符串,时间复杂度为 O(K)。
        4. 整体排序操作的时间复杂度为 O(K log K)。
      2. 使用字符计数作为键:
        1. 每次对字符串进行遍历,时间复杂度为O(K)
    3. Map 操作
      • map.has(sorted)map.get(sorted) 的时间复杂度平均为 O(1)(假设良好的哈希函数)。
      • map.set(...) 的时间复杂度平均为 O(1)。
      • [...] 操作数组的时间复杂度为 O(1),因为只是创建一个新数组引用。
    4. 转换 Map 为数组
      • Array.from(map.values()) 的时间复杂度为 O(N)。
  • 总时间复杂度
    • 遍历 N 个字符串,避免了排序操作,字符串长度为K。
    • 因此,总时间复杂度为 O(N * K)

空间复杂度

  • 主要空间占用
    1. Map 存储
      • 最坏情况下,没有任何两个字符串是异位词,每个字符串对应一个唯一的键。
      • Map 中存储了 N 个键,每个键的长度为 K(排序后的字符串)。
      • Map 的空间复杂度为 O(N * K)。
    2. 中间变量
      1. 排序:
        1. sorted 字符串占用 O(K) 空间。
        2. split('') 生成的字符数组占用 O(K) 空间。
        3. sort 操作生成的临时数组占用 O(K) 空间。
        4. 因为这些是逐步处理的,中间空间为 O(K)。
      2. 字符数组:
        1. 创建长度为26的字母数组,常数空间,空间复杂度为O(1)
    3. 输出数组
      • Array.from(map.values()) 返回一个包含所有字符串的二维数组,空间复杂度为 O(N * K)。
  • 总空间复杂度
    • 主要的空间占用来自于 Map 和输出数组,总空间复杂度为 O(N * K)

code

/**
 * @param {string[]} strs
 * @return {string[][]}
 */
var groupAnagrams = function (strs) {
    const map = new Map();
    strs.forEach(item => {
        // 创建一个长度为26的数组,统计每个字母出现的次数
        const charCount = Array(26).fill(0);
        for (let char of item) {
            charCount[char.charCodeAt(0) - 97]++;
        }
        // 将字符计数数组转换为字符串作为键
        const key = charCount.join('#');
        if (map.has(key)) {
            map.get(key).push(item);
        } else {
            map.set(key, [item]);
        }
    });
    return Array.from(map.values());
};