优选算法——哈希表

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

👇作者其它专栏:

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


相关题解

1.两数之和

算法思路:

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

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

●因为哈希表中查找元素的时间复杂度为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;
    }
};
相关推荐
m0_748839491 小时前
利用C 图形界面展示MATLAB算法的高效混合编程实践
开发语言·算法·matlab
阿牛大牛中1 小时前
阿里-RecGPT-Mobile
大数据·人工智能·算法
RH2312111 小时前
2026.5.17数据结构 八大排序
数据结构·算法·排序算法
加号31 小时前
【C#】 实现 CRC16 校验:原理、算法与工程实践
算法·c#
蜡笔小马1 小时前
12.C++设计模式-模板方法模式
c++·设计模式·模板方法模式
江屿风1 小时前
【C++笔记】内存管理流食般投喂
开发语言·c++·笔记
雪度娃娃1 小时前
行为型设计模式——备忘录模式
服务器·c++·设计模式·备忘录模式
khalil10201 小时前
代码随想录算法训练营Day-55 图论06 | 108.冗余连接、109.冗余连接II
c++·算法·leetcode·图论·并查集
进击的荆棘1 小时前
优选算法——字符串
开发语言·c++·算法·leetcode·字符串