哈希表

基本知识

集合 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::set 红黑树 有序 O(log n) O(log n)
std::multiset 红黑树 有序 O(logn) O(logn)
std::unordered_set 哈希表 无序 O(1) O(1)
映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::map 红黑树 key有序 key不可重复 key不可修改 O(logn) O(logn)
std::multimap 红黑树 key有序 key可重复 key不可修改 O(log n) O(log n)
std::unordered_map 哈希表 key无序 key不可重复 key不可修改 O(1) O(1)
判断一个元素是否出现过的场景也应该第一时间想到哈希法!

242.有效的字母异位词

力扣题目链接

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:
输入: s = "anagram", t = "nagaram"
输出: true

示例 2:
输入: s = "rat", t = "car"
输出: false

说明:
你可以假设字符串只包含小写字母。

题解:26个字母计数即可

383.赎金信

与242类似,以第二个字符串为备选,判断是否可以填满第一个字符串

49.字母异位词分组

unordered_map的key必须是可以hash的,官方兼容了基本数据类型的hash(如 int, string, char, size_t)
官方写法把array<int,26>即统计每个字母有多少个的数组,用一个hash表示,然后将该hash作为unordered_map的key来索引每个异位词。
有一个简便写法,可以自己制作hash,例如用“a2b1”来表示“aab”,string是可以作为索引的。

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> map;
        for(string str:strs){
            int cnts[26]={0};
            for(char c:str){
                cnts[c-'a']++;
            }
            string key="";
            for(int i=0;i<26;i++){
                if(cnts[i]!=0){//这个判断不必须,单纯剩空间
                    key.push_back(i+'a');//字符串拼接可以直接+,但在当前语义会有歧义所以用push_back
                    //但push_back只能添加一位字符,所以要保证添加的字符ASCII码在(0~127)之间
                    key+=to_string(cnts[i]);//所以这里直接使用+=,因为若该字符数量大于127则会报错
                }
                
            }
            map[key].push_back(str);
        }
        vector<vector<string>> res;
        for(auto& i:map){
            res.push_back(i.second);
        }
        return res;
    }
};

官方代码

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;
    }
};

string的基本用法

一、构造

std::string s1 = "Hello";          // 从字符串字面量构造
std::string s2("World");           // 构造函数形式
std::string s3(5, 'a');            // 重复字符 'a' 5 次 -> "aaaaa"
std::string s4 = s1 + " " + s2;    // 字符串拼接
string s(1, ascii_code);           // 构建单个ASCII码的string    

二、常用操作

1. 获取长度

s1.length();      // 或 s1.size();

2. 拼接字符串

std::string s = "Hello";
s += " World";    // => "Hello World"
s.append("!");    // => "Hello World!"
s.push_back(i+'a'); //防止使用ASCII码时产生歧义,但是只能添加单个字符

3. 子串提取

std::string sub = s.substr(0, 5);   // 从下标0开始,取5个字符 => "Hello"

4. 查找字符串或字符

size_t pos = s.find("World");      // 返回起始下标,找不到返回 string::npos
if (pos != std::string::npos) {
    std::cout << "Found at " << pos;
}

5. 替换子串

s.replace(6, 5, "C++");   // 从下标6开始,替换5个字符为"C++" => "Hello C++!"

6. 插入和删除

s.insert(5, ",");         // 在下标5插入","
s.erase(5, 1);            // 从下标5开始删除1个字符

三、字符访问

char c = s[0];            // 直接访问,不做越界检查
char d = s.at(1);         // 有越界检查(抛异常)

// 遍历字符串每个字符
for (char ch : s) {
    std::cout << ch;
}

四、字符串和数字转换(C++11 起)

string -> int / double

std::string s = "123";
int x = std::stoi(s);       // 字符串转 int
double d = std::stod("3.14");

int / double -> string

int a = 42;
std::string s = std::to_string(a);   // => "42"

1002. 查找常用字符

力扣题目链接

给你一个字符串数组 words ,请你找出所有在 words 的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案。

示例 1:

输入:words = ["bella","label","roller"]
输出:["e","l","l"]

示例 2:

输入:words = ["cool","lock","cook"]
输出:["c","o"]

提示:

1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] 由小写英文字母组成

题解,将每个字符串中字符出现频率统计出来算最小值即可

vector容器中emplace_backpush_back 的区别

emplace_back省略了构造变量的步骤

ans.push_back(std::string(1, 'c'));
ans.emplace_back(1, 'c');  // 推荐:直接构造,简洁高效
posted @ 2025-06-25 21:57  Diffelentor  阅读(19)  评论(0)    收藏  举报