算法——哈希表

哈希表简介

**是什么:**存储数据的容器
有什么用 :快速查找某个元素,时间复杂度O(1),空间复杂度O(n)

**什么时候使用哈希表:**频繁查找某一个数(这里不要忘了之前的二分,时间复杂度O(logN))
怎么用哈希表 : 1.容器 2.用数组模拟简易哈希表

两数之和

两数之和

题目解析

  • 该数组中找出 **和为目标值 **target 的那 两个 整数,并返回它们的数组下标。
  • 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
  • 按任意顺序返回答案

算法原理

解法一:暴力解法

之前的枚举是,固定一个指针,向后移动另一个指针开始遍历,直到找到目标值。这次枚举我们依然先固定一个指针,然后遍历这个数之前的数字,遍历完仍然向后移动另一个指针。时间复杂度O(n2)

解法二:使用哈希表优化

暴力解法遍历指针之前的数字 所消耗的时间复杂度是O(n),如果我们将所要遍历的数字放到哈希表里,那我们的就只需要花费O(1)的时间复杂度就能够找到。总体时间复杂度消耗为O(n),空间复杂度也为O(n);典型的空间换时间。在哈希表里存储的是数字和下标一起绑定存储

为什么之前的遍历不好用呢?

把数组全放入哈希表中时,如果我们所要找的数和自身相等时,那就会找到自身,这是不符合题意的。这种情况是需要特判的。但我们运用上面的的哈希表做优化就不会遇到这种边界问题。

代码实现

cpp 复制代码
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};
    }
};

判定是否为字符重排

判断是否为字符重排

题目解析

给定两个由小写字母组成的字符串 s1 和 s2

其中一个字符串的字符重新排列后,能否变成另一个字符串。

算法原理

解法一:模拟 :将字符串所有组成可能性全部列出来,然后进行比较。但是时间复杂度是指数级别的,非常恐怖
解法二:哈希表: 如果s1能够重排s2,那么每个字符出现的次数肯定相同。那么我们可以使用哈希表,但是我们是使用容器还是使用数组模拟呢。如果使用容器,要找hash1里字符的int和hash2里对应字符的int进行比较,较为麻烦。因为题目中说了只由小写字母组成,

**优化:只使用一个哈希表:**只用一个哈希表记录s1字符出现的次数,然后遍历s2,s2中出现的字符在hash1中减掉1即可。当两个字符串的⻓度不相等的时候,是不可能构成互相重排的,直接返回false

代码实现

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)
    {
    //a映射到字符下标为0,所以-'a'
    hash[ch - 'a']--;
    if(hash[ch - 'a'] < 0) return false;
    }

    return true;
    }
};

存在重复元素I

存在重复元素I

题目解析

如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

算法原理

和两数之和相同,固定一个数,找在他之前的数有没有出现重复。这里我们的hash表只需要存一个k值就行

代码实现

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

存在重复元素II

存在重复元素II

题目解析

判断数组中是否存在两个 不同的索引 _ i 和 _j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k

算法原理

解法:哈希表

表里存储字符和下标,将数组中的数字和其对应的下标一起绑定存入hash表中。开始移动。当发现前面由相同元素时,将两个下标相减,发现不符合条件,将1(紫色指针所指的)放入hash表中,此时存入的<1,3>就把最开始的<1,0>覆盖掉了。继续向后移动。当移动到下一个1时,只需要考虑里第三个1最近位置的1(即第二个1)即可。因为如果最远位置的符合条件(第一个1),那么近的位置也符合。

思考题:如果数组内存在⼤量的「重复元素」,⽽我们判断下标所对应的元素是否符合条件的时候,需要将不同下标的元素作⽐较,怎么处理这个情况呢?

答:这⾥运⽤了⼀个「⼩贪⼼」。我们按照下标「从⼩到⼤」的顺序遍历数组,当遇到两个元素相同,并且⽐较它们的下标时,这两个下标⼀定是距离最近的,因为:

• 如果当前判断符合条件直接返回 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]))
        {
          if(i - hash[nums[i]] <= k) return true;
        }

    hash[nums[i]] = i;
    }
    return false;
    }
};

字母异位词分组

字母异位词分组

题目解析

  • 判断字母异位词,并且按组返回

算法原理

解法:哈希表

  1. 判断两个字符串是否为字母异位词:我们可以用哈希表判断,这里我们使用排序,虽然这样时间复杂度更高,但是代码好写一些。按照ASCII码值排序
  2. 如何分组:借助容器,我们将k值定位为string,Value值定义为字符串数组string(K-V)。遍历第一个字符串eat,按照ASCII码值排序之后为aet,这里作为k值的string,然后将原始数组中的字符串开始作为V值遍历比较。将eat排完序后发现hash表里由aet,存入,然后继续向后遍历。若发现排序完之后没有,创建一个新的(如ant)再继续比较

代码实现

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. 结果提取出来
    vector<vector<string>> ret;
    for(auto& [x, y] : hash)
    {
        ret.push_back(y);
    }

    return ret;
    }
};
相关推荐
争不过朝夕,又念着往昔3 分钟前
Redis中Hash(哈希)类型的基本操作
数据库·redis·缓存·哈希算法
繁依Fanyi25 分钟前
使用 Spring Boot + Redis + Vue 实现动态路由加载页面
开发语言·vue.js·pytorch·spring boot·redis·python·算法
aloha_78931 分钟前
B站宋红康JAVA基础视频教程(chapter14数据结构与集合源码)
java·数据结构·spring boot·算法·spring cloud·mybatis
临沂堇1 小时前
CCF刷题计划——训练计划(反向拓扑排序)
数据结构·c++·算法·拓扑·ccf
铁匠匠匠1 小时前
【C总集篇】第八章 数组和指针
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
Unicorn建模1 小时前
2024“华为杯”中国研究生数学建模竞赛(E题)深度剖析|数学建模完整过程+详细思路+代码全解析
python·算法·数学建模
咕咕吖1 小时前
二叉树的层序遍历(c)
数据结构·算法
“JB...One”2 小时前
openssl-AES-128-CTR加解密结构体
linux·数据结构·算法·ssl
爱数模的小云2 小时前
【华为杯】2024华为杯数模研赛D题 解题思路
算法·华为
好记性+烂笔头2 小时前
hot100-438. 找到字符串中所有字母异位词
算法