【专题十】哈希表

📝前言说明:

  • 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础python入门基础C++学习笔记Linux
🎀CSDN主页 愚润泽

你可以点击下方链接,进行该专题内不同子专题的学习

点击链接开始学习
双指针(1)双指针(2)
双指针(3)双指针(4)
滑动窗口(1)滑动窗口(2)
滑动窗口(3)滑动窗口(4)
二分查找(1)二分查找(2)
前缀和(1)前缀和(2)
前缀和(3)位运算(1)
位运算(2)模拟算法
快速排序归并排序
链表哈希表
字符串
队列 + 宽搜优先级队列
BFS 解决 FloodFillBFS 解决最短路径
多源 BFSBFS 解决拓扑排序

题单汇总链接:点击 → 题单汇总(暂时未整理,因为还没刷完)


导论

  • 哈希表理论:映射(哈希函数,又涉及哈希冲突…)
  • 哈希表是一个存储数据的容器,查找速度 O ( 1 ) O(1) O(1)
  • 当需要快速查找某个元素的时候 → 使用哈希表(或者二分 O ( l o g N ) O(logN) O(logN)
  • 使用哈希表
    • 自带的:unordered_map
    • 使用数组模拟<index, a[index]>(好映射且数据范围小的,有负数索引的时候不建议用)

1. 两数之和

题目链接:https://leetcode.cn/problems/two-sum/description/
在这里插入图片描述

个人解

代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        unordered_map<int, int> hash; // <元素, 下标>
        for(int i = 0; i < nums.size(); i++)
        {
            int x = target - nums[i];
            if(hash.count(x)) return {hash[x], i};
            hash[nums[i]] = i; // 会覆盖
        }
        // 编译器要求必须返回
        return {-1, -1};
    }
};

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)


面试题 01.02. 判定是否互为字符重排

题目链接:https://leetcode.cn/problems/check-permutation-lcci/description/
在这里插入图片描述

个人解

思路:

  • 很妙:一个 + 一个 -,并且在-修改哈希表的时候就直接判断是否满足要求

屎山代码:

class Solution {
public:
    bool CheckPermutation(string s1, string s2) {
        int m = s1.size(), n = s2.size();
        if(m != n) return false;
        int hash[26];
        for(auto c: s1)
            hash[c - 'a']++;
        for(auto c: s2)
            if(--hash[c - 'a'] < 0)
                return false;
        return true;
    }
};

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)


217. 存在重复元素

题目链接:https://leetcode.cn/problems/contains-duplicate/description/
在这里插入图片描述

个人解

屎山代码:

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_map<int, int> hash; // <数字, 次数>
        for(auto x: nums)
            if(++hash[x] >= 2)
                return true;
        return false;
    }
};

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)


219. 存在重复元素 II

题目链接:https://leetcode.cn/problems/contains-duplicate-ii/description/
在这里插入图片描述

个人解

屎山代码:

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) 
    {
        unordered_map<int, int> hash; // 记录某个数字最近一次出现的索引
        for(int i = 0; i < nums.size(); i++)
        {
            int x = nums[i];
            if(hash.count(x) && (i - hash[x] <= k))
                return true;
            hash[x] = i; // 如果是第一次出现或者不符合,则 添加/ 更新索引
        }    
        return false;
    }
};

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)


49. 字母异位词分组

题目链接:https://leetcode.cn/problems/group-anagrams/description/
在这里插入图片描述

个人解

屎山代码:
超时了,时间复杂度: O ( n 2 ) O(n^2) O(n2)

class Solution {
public:
    bool is_yiwei(string& a, string& b)
    {
        vector<int> hash(26, 0);
        int m = a.size(), n = b.size();
        if(m != n) return false;
        for(auto x: a)
            hash[x - 'a']++;
        for(auto x: b)
            if(--hash[x - 'a'] < 0)
                return false;
        return true;
    }
    vector<vector<string>> groupAnagrams(vector<string>& strs)
    {
        // 将哈希表相同的字符串放在一个 vector 里面
        int n = strs.size();
        vector<bool> check(n, false);   // 记录当前的字符串有没有被放入 
        vector<vector<string>> ans;
        for(int i = 0; i < n; i++)   // strs[i] 是基准
        {
            if(check[i]) continue; // 说明当前的基准已经和前面的基准匹配过了
            vector<string> path;
            path.emplace_back(strs[i]);
            for(int j = i + 1; j < n; j++)
            {
                if(is_yiwei(strs[i], strs[j]))
                {
                    path.emplace_back(strs[j]);
                    check[j] = true;
                }
            }
            ans.emplace_back(path);
        }
        return ans;
    }
};

优质解

思路:

  • 对于两个词,我们如何判断是不是异位词?
    • 方法一:相同异位词对应的哈希表相同(可是哈希表的键不能是哈希表)
    • 方法二:相同的异位词sort以后是相同的字符串
  • 把容器进行组合,哈希表:<string, vector<string>>
    • string是排序后的字符串
    • vector<string>是异位词的一组
    • 我们通过把异位词排序找到要添加的vector,然后把原来的异位词加进去

代码:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    {
        unordered_map<string, vector<string>> hash;
        for(auto s:strs)
        {
            string tmp = s;
            sort(tmp.begin(), tmp.end());
            hash[tmp].emplace_back(s);
        }
        vector<vector<string>> ans;
        for(auto p:hash)
            ans.emplace_back(p.second);
        return ans;
    }
};

时间复杂度: O ( N ∗ K l o g K ) ) O(N*KlogK)) O(NKlogK)), N 是字符串数量,K是字符串长度
空间复杂度: O ( N ∗ K ) O(N*K) O(NK)


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚润泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值