优选算法——哈希表

💁‍♂️个人主页:进击的荆棘

👇作者其它专栏:

《数据结构与算法》《算法》《C++起始之路》


相关题解

1.两数之和

算法思路:

●若我们可以事先将【数组内的元素】和【下标】绑定在一起存入【哈希表】中,然后直接在哈希表中查找每一个元素的target-numsi,就能快速的找到【目标和的下标】。

●小技巧:可以不用将元素全部放入到哈希表之后,再来二次遍历(因为要处理元素相同的情况)。而是在将元素放入到哈希表中的【同时】,直接来检查表中是否已经存在当前元素所对应的目标元素(既target-numsi)。若它存在,就说明已经找到了对应解,并立即将其返回。无需将元素全部放入哈希表中,提高效率。

●因为哈希表中查找元素的时间复杂度为O(1),遍历一遍数组的时间复杂度为O(N),因此可以将时间复杂度降到O(N)。

这是一个典型的【用空间换时间】的方式。

cpp 复制代码
//法一:暴力枚举
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i=0;i<nums.size();i++){
            for(int j=i-1;j>=0;j--){
                if(nums[i]+nums[j]==target){
                    return {i,j};
                }
            }
        }
        return {0,0};
    }
};
//法二:用哈希表做优化
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> hash;//<nums[i],i>
        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};
    }
};

2.判定是否互为字符重排

算法思路:

1.当两个字符串的长度不相等的时候,是不可能构成互相重排的,直接返回false;

2.若两个字符串能够构成互相重排,那么每个字符串中【各个字符】出现的【次数】一定是相同的。因此,可以分别统计出这两个字符串中各个字符出现的次数,然后逐个比较是否相等即可。这样的话,就可以选择【哈希表】来统计字符串中字符出现的次数。

cpp 复制代码
class Solution {
public:
    bool CheckPermutation(string s1, string s2) {
        if(s1.size()!=s2.size()) return false;

        int hash[26]={0};
        for(auto ch:s1){
            hash[ch-'a']++;
        }
        for(auto ch:s2){
            hash[ch-'a']--;
            if(hash[ch-'a']<0) return false;
        }
        return true;
    }
};

3.存在重复元素

算法思路:

分析题目,出现【至少两次】的意思就是数组中存在重复的元素,因此可以无需统计元素出现的数目。仅需在遍历数组的过程中,检查当前元素【是否在之前已经出现过】即可。

因此可以利用哈希表,仅需存储【数组内的元素】。在遍历数组的时候,一边检查哈希表中是否已经出现过当前元素,一边将元素加入到哈希表中。

cpp 复制代码
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> hash;
        for(auto& e:nums){
            if(hash.count(e)) return true;
            else hash.insert(e);
        }
        return false;
    }
};

4.存在重复元素 II

算法思路:

解决该问题需要我们快速定位到两个信息:

●两个相同的元素;

●这两个相同元素的下标。

因此,可以使用【哈希表】,令数组内的元素做key值,该元素所对应的下标做val值,将【数组元素】和【下标】绑定到一起,存入到【哈希表】中。

思考:

若数组内存在大量的【重复元素】,而判断下标所对应的元素是否符合条件的时候,需要将不同下标的元素作比较,该如何处理?

**答:**这里运用了一个【小贪心】。

按照下标【从小到大】的顺序遍历数组,当遇到两个元素相同,并且比较它们的下标时,这两个下标一定是距离最近的,因为:

●若当前判断符合条件直接返回true,无需继续往后查找。

●若不符合条件,那么前一个下标一定不可能与后续相同元素的下标匹配(因为下标在逐渐变大),所以就可以大胆舍去前一个存储的下标,转而将其换成新的下标,继续匹配。

cpp 复制代码
class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_map<int,int> hash;
        for(int i=0;i<nums.size();i++){
            if(hash.count(nums[i])==1){
                //i的下标一定比之前存的下标大
                if(i-hash[nums[i]]<=k)
                    return true;
            }
            //因为abs(i-j)<=k,则两个相同的值一定是越近,绝对值之差越小,可以放心覆盖之前存的下标
            hash[nums[i]]=i;
        }
        return false;
    }
};

5.字母异位词分组

算法思路(哈希表+排序):

互为字母异位词的单词有一个特点:将它们【排序】后,两个单词应是【完全相同】的。

所以,可以利用这个特性,将搭单词按照字典序排序,若排序后的单词相同的话,就划分到同一组中。

这时就要处理两个问题:

●排序后的单词与原单词需要能相互映射;

●将排序后相同的单词,【划分到同一组】;

利用语言提供的【容器】的强大的功能就能实现这两点:

●将排序后的字符串(string)当作哈希表的key值;

●将字母异位词数组(string\[\])当成val值。

定义一个【哈希表】即可解决问题。

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> hash;
        //1.将字母异位词分组
        for(auto& s:strs){
            string tmp=s;
            //通过排序来确定是否为异位词
            sort(tmp.begin(),tmp.end());
            hash[tmp].push_back(s);
        }
        //2.将结果提取到ret中
        vector<vector<string>> ret;
        //第一种写法
        // for(auto& e:hash){
        //     ret.push_back(e.second);
        // }
        //第二种写法
        for(auto& [x,y]:hash){
            ret.push_back(y);
        }
        return ret;
    }
};
相关推荐
fqbqrr8 小时前
2606C++,C++构的多态
开发语言·c++
小欣加油9 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
lqqjuly9 小时前
前沿算法深度解析(二)
人工智能·算法·机器学习
Yolo_TvT10 小时前
C++:析构函数
c++
徐小夕10 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github
akunkuntaimei11 小时前
2026年高考数学各省真题及答案(完整版)
算法·高考
Hello:CodeWorld11 小时前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法
8Qi813 小时前
LeetCode 516:最长回文子序列
算法·leetcode·职场和发展·动态规划
搬砖魁首14 小时前
基础能力系列 - 多线程2 - 条件变量
c++·rust·条件变量·原子类型·线程同步互斥
youngerwang14 小时前
【从搬运工到协处理器:网卡芯片架构、算法、验证与边缘演进深度剖析】
网络·算法·架构·芯片