【数据结构与算法】哈希专题

目录

[​​​​​​【题目链接】217. 存在重复元素 - 力扣(LeetCode)](#【题目链接】217. 存在重复元素 - 力扣(LeetCode))

[【题目链接】1. 两数之和 - 力扣(LeetCode)](#【题目链接】1. 两数之和 - 力扣(LeetCode))

[【题目链接】49. 字母异位词分组 - 力扣(LeetCode)](#【题目链接】49. 字母异位词分组 - 力扣(LeetCode))

[【题目链接】128. 最长连续序列 - 力扣(LeetCode)](#【题目链接】128. 最长连续序列 - 力扣(LeetCode))

[【题目链接】560. 和为 K 的子数组 - 力扣(LeetCode)](#【题目链接】560. 和为 K 的子数组 - 力扣(LeetCode))

(一)哈希基础

哈希种类

哈希表的特点

C++中哈希常见用法总结

(二)补充


​​​​​​【题目链接】217. 存在重复元素 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> set;
        for(int i=0;i<nums.size();i++){
            if(set.count(nums[i]))
                return true;
            set.insert(nums[i]);
        }
        return false;
    }
};

**解题思路:**利用哈希集合的无重复元素的性质,将数组依次存入哈希集合中,边存边查是否有重复(当前数组值是否已存入过哈希集合)。

**时间复杂度:**O(n) 每个元素只有一次检查+加入。

**空间复杂度:**O(n) 最坏情况需要存入所有元素才能得到结果。

【题目链接】1. 两数之和 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> map;
        for(int i=0;i<nums.size();i++){//枚举两个数中靠右侧的数a,维护哈希表存前面的[0,i-1]去找b
            int a=nums[i];
            int b=target-a;
            if(map.find(b)!=map.end())
                return {i,map.find(b)->second};
            map[a]=i;
        }
        return {};
    }
};

**解题思路:**利用哈希表的快速查找思想,假设b+a=target,此时只需要固定一个,去哈希表找另一个即可。遍历数组中的每个值numsi做一次a(两个数中靠右侧的数),维护一个哈希表来存储已遍历过的元素,对于每个数去哈希表中找是否有目标b。

**时间复杂度:**O(n) 需要遍历一遍所有元素才能得到结果,在哈希表中的都是O(1)。

**空间复杂度:**O(n) 哈希表的构建。

【题目链接】49. 字母异位词分组 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> map;
        for(auto i:strs){
            string key=i;
            sort(key.begin(),key.end());
            map[key].push_back(i);
        }
        vector<vector<string>> result;
        for(auto k :map){
            result.push_back(k.second);
        }
        return result;
    }
};

**解题思路:**利用排序+哈希表无重复元素和查找快的性质,维护pair<key, value>哈希表记录字母异位词(两个字符串排序之后相等)<模版, 此模版下排序前的字符串构成的数组>。

**时间复杂度:**O(nklogk),k是所有字符串中最长字符串的长度。 排序、遍历

**空间复杂度:**O(nk) 哈希表存储、排序(临时字符串哈希开销)

【题目链接】128. 最长连续序列 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> set_nums;
        for(auto i:nums){
            set_nums.insert(i);
        }
        int max=0;
        for(auto i:set_nums){
            if(!set_nums.count(i-1)){//当前数-1不存在的时候,它是起点才有可能最大
                int current=i;
                int flag=1;
                while(set_nums.count(current+1)){
                    current++;
                    flag++;
                }
                if(flag>max) max=flag;
            }
        }
        return max;
    }
};

**解题思路:**利用哈希集合查找快和无重复元素的优势,以及贪心思想,先将数组存入无重复元素的哈希集合,遍历集合中的每个元素i,看集合中是否存在i+1,...,i+k的值,并统计长度为k+1,过程中保存最长的序列长度。(考虑最优解不可能出现在"数-1"存在的数开头的序列上,可以优化时间,只枚举不存在"数-1"的数为起点)

时间复杂度: O(n) 因为每个元素恰好被访问一次。(for枚举所有数n次,while循环枚举所有非起点元素,而非起点元素最多也只有n个)

**空间复杂度:**O(n) 哈希表存储

【题目链接】560. 和为 K 的子数组 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        vector<int> sum_nums;
        int sum=0;
        for(auto i:nums){
            sum+=i;
            sum_nums.push_back(sum);
        }
        int res=0;
        unordered_map<double,int> map;
        map[0]=1;
        for(auto i:sum_nums){
            int target=i-k;
            if(map.count(target))
                res+=map[target];
            map[i]++;
        }
        return res;
    }
};

**解题思路:**利用前缀和+哈希两数之和的思想。问题是找到x1+x2+...+xm=k,子数组的和可以转化为两个前缀和之差,即Si-Sj=k是目标(类似前面两数之和的目标)。枚举靠右的Si,找是否出现过Si-k。维护键值对哈希表记录每个前缀和的出现次数res,即为n个子数组以位置i结尾和为k。

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

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

(一)哈希基础

哈希种类

1、哈希集合(set / unordered_set):只存单个元素,元素本身就是 "唯一标识",没有 first /second,底层红黑树有序,平均时间复杂度O(nlogn)

2、哈希表(map / unordered_map):存 key-value 键值对,元素是 pair,所以才有 k.first(键)、k.second(值),底层哈希映射哈希表无序,平均时间复杂度O(n)

哈希表的特点

哈希表是一种基于哈希函数(Hash Function)的数据结构,用于实现键值对的快速存储和查找。它的主要特点是:

  • 快速查找:平均情况下,哈希表的查找、插入和删除操作的时间复杂度都是 O(1)。
  • 键值对存储:哈希表存储的是键值对,每个键(Key)唯一对应一个值(Value)。
  • 哈希函数:通过哈希函数将键映射到哈希表中的位置,从而实现快速存取。

C++中哈希常见用法总结

哈希集合

#include<unordered_set>

unordered_set<int> set; //哈希集合

set.erase(numsi); //删除数字

set.insert(numsi); //插入数字

①set.count(numsi) ②set.find(b)!=set.end() //是否存在numsi,存在返回true

哈希表

#include<unordered_map>

unordered_map<int,int> map; //哈希表,类型任意

mapb=i; //b对应的值为i

map.erase(b); //删除key为b的对

①map.find(b)!=map.end() ②map.count(b) //目标是否存在

常见坑:

  • map.find(b)->second //key为b对应的val
  • mapb //若存在key是b,则返回val;不存在,插入新key=b,val=默认构造值,再返回val
  • //取出所有的second里的值到result
  • for(auto k :map)
  • result.push_back(k.second);//k.second取val,k.first取key

(二)补充

#include<bits/stdc++.h> //万能头文件

#include <iostream> //引入输入输出流头文件,C++ 标准输入输出库

cin>>; cout<<x<<endl;

using namespace std; //打开 std 标准命名空间(可以简写不写std::)

排序函数:

#include<algorithm>

sort(key.begin(),key.end());//默认从小到大排序

学习中,诚挚希望有心者指正和交流,经验或者方法都可。

相关推荐
LCG米4 分钟前
机器人控制系统与运动规划:从RRT算法到ROS move_base实战
算法·机器人
QiLinkOS10 分钟前
第三视觉理解徐玉生与他的商业活动(26)
大数据·c++·人工智能·算法·开源协议
手写码匠26 分钟前
手写 LLM 结构化输出引擎 —— 从 JSON Schema 约束到类型安全的数据提取
人工智能·深度学习·算法·aigc
zhiSiBuYu051733 分钟前
重排序(Rerank)提升检索准确率实战指南
开发语言·python·算法
月疯42 分钟前
华为手环的部分功能
算法
chase_my_dream1 小时前
FAST-LIO src/IMU_Processing.hpp 完整详细讲解
c++·状态模式·slam
郭梧悠1 小时前
算法:有效的括号
python·算法·leetcode
atunet1 小时前
关于算法设计模式的演化与编程范式变迁的技术7
算法·设计模式
Jerry1 小时前
LeetCode 27. 移除元素
算法
旖-旎1 小时前
《LeetCode 1137 第N个泰波那契数 和 LeetCode 三步问题》
c++·算法·leetcode·动态规划