字母异位词分组(每天刷力扣hot100系列)

题目介绍:

方法1:遍历法

cpp 复制代码
#include <algorithm>

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    {
        vector<string> beg(strs);
        for (string& k : beg) 
            sort(k.begin(), k.end());  // 排序作为键

        vector<vector<string>> rel;
        vector<bool> visited(strs.size(), true);  // 使用visited标记

        for(int i=0;i<beg.size();i++)
        {
            vector<string> temp;
            if(visited[i]==true)
            {
                temp.push_back(strs[i]);
                for(int j=i+1;j<beg.size();j++)
                {
                    if(beg[i]==beg[j])
                    {
                        temp.push_back(strs[j]);
                        visited[j]=false;
                    }
                }
                rel.push_back(temp);
            }

        }
        return rel;
    }
};

(博主自己敲的方法,不推荐,适合理解)

代码思路

  1. 创建beg数组,是strs的拷贝,然后对beg中的每个字符串进行排序(这样同一个变位词组排序后字符串相同)。

  2. 然后遍历beg数组,对于每个字符串,如果它是true,则创建一个临时组,将当前字符串加入(注意:这里加入的是排序后的字符串,但实际需要的是原字符串)。 3. 然后内层循环从i+1开始,找后面所有与beg[i]相同的字符串,将对应的原字符串(strs[j])加入临时组,并将beg[j]标记为false(表示已经处理过)。

  3. 最后将临时组加入结果rel中。

方法2:哈希桶

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    {
        //哈希桶
        unordered_map<string,vector<string>> mp;//创建一个字符串和字符串数组对应键值的哈希表
        for(auto str:strs)//迭代器将数组里的字符串全部排序,然后在对应的字符串键处存放原字符串
        {
            string key=str;
            sort(key.begin(),key.end());
            mp[key].push_back(str);//这里如果用emplace_back内存消耗更少
        }

        vector<vector<string>> rel;
        for(auto it=mp.begin();it!=mp.end();it++)//遍历哈希桶
        {
            rel.push_back(it->second);//将字符串组插入rel中,这里如果用emplace_back内存消耗更少
        }
        return rel;
    }
};

复杂度分析

1.时间复杂度O(nklogk),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的的最大长度。需要遍历 n 个字符串,对于每个字符串,需要 O(klogk) 的时间进行排序以及 O(1) 的时间更新哈希表,因此总时间复杂度是 O(nklogk)。

2.空间复杂度O(nk),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的的最大长度。需要用哈希表存储全部字符串。

核心区别

特性 push_back() emplace_back()
工作原理 构造临时对象 → 拷贝/移动到容器 直接在容器内存中构造对象
参数 接受对象本身 接受对象的构造参数
效率 可能额外构造临时对象(有拷贝开销) 避免临时对象(更高效)
适用场景 添加已存在的对象 直接构造新对象

这个方法不同的是不需要根据每个的字符串往后遍历,而是直接放进哈希桶,最后把vector<string>提出来就行。

力扣上还有个计数的方法比较复杂,但是时间复杂度和空间复杂度进一步降低了:

方法3:计数

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // 自定义对 array<int, 26> 类型的哈希函数
        auto arrayHash = [fn = hash<int>{}] (const array<int, 26>& arr) -> size_t {
            return accumulate(arr.begin(), arr.end(), 0u, [&](size_t acc, int num) {
                return (acc << 1) ^ fn(num);
            });
        };

        unordered_map<array<int, 26>, vector<string>, decltype(arrayHash)> mp(0, arrayHash);
        for (string& str: strs) {
            array<int, 26> counts{};
            int length = str.length();
            for (int i = 0; i < length; ++i) {
                counts[str[i] - 'a'] ++;
            }
            mp[counts].emplace_back(str);
        }
        vector<vector<string>> ans;
        for (auto it = mp.begin(); it != mp.end(); ++it) {
            ans.emplace_back(it->second);
        }
        return ans;
    }
};

复杂度分析

1.时间复杂度:O(n(k+∣Σ∣)),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的的最大长度,Σ 是字符集,在本题中字符集为所有小写字母,∣Σ∣=26。需要遍历 n 个字符串,对于每个字符串,需要 O(k) 的时间计算每个字母出现的次数,O(∣Σ∣) 的时间生成哈希表的键,以及 O(1) 的时间更新哈希表,因此总时间复杂度是 O(n(k+∣Σ∣))。

2.空间复杂度:O(n(k+∣Σ∣)),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的最大长度,Σ 是字符集,在本题中字符集为所有小写字母,∣Σ∣=26。需要用哈希表存储全部字符串,而记录每个字符串中每个字母出现次数的数组需要的空间为 O(∣Σ∣),在渐进意义下小于 O(n(k+∣Σ∣)),可以忽略不计。

喜欢的话就关注我吧~~~求关注求赞求收藏~~~^-^

相关推荐
杨DaB1 小时前
【SpringMVC】拦截器,实现小型登录验证
java·开发语言·后端·servlet·mvc
近津薪荼1 小时前
c++详解(宏与内联函数,nullptr)
开发语言·c++
淮北4942 小时前
STL学习(十一、常用的算数算法和集合算法)
c++·vscode·学习·算法
糖葫芦君2 小时前
玻尔兹曼分布与玻尔兹曼探索
人工智能·算法·机器学习
AA陈超4 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 #06-11:游戏后效果执行
c++·游戏·ue5·游戏引擎·虚幻
天若有情6737 小时前
【python】Python爬虫入门教程:使用requests库
开发语言·爬虫·python·网络爬虫·request
寒水馨7 小时前
Java 17 新特性解析与代码示例
java·开发语言·jdk17·新特性·java17
启山智软7 小时前
选用Java开发商城的优势
java·开发语言
秃然想通7 小时前
掌握Python三大语句:顺序、条件与循环
开发语言·python·numpy