算法思想总结:哈希表

news2024/12/25 16:00:27

一、哈希表剖析

1、哈希表底层:通过对C++的学习,我们知道STL中哈希表底层是用的链地址法封装的开散列

2、哈希表作用:存储数据的容器,插入、删除、搜索的时间复杂度都是O(1),无序。

3、什么时候使用哈希表:需要频繁查找数据的场景。

4、OJ中如何使用哈希表???

(1)STL中的容器(适用所有场景,比如字符串相关、数据映射下标)

(2)数组模拟简易哈希表(减小时间损耗,容器的封装有一定代价)—>大多以下两种情况适用

情况1:(char)涉及到字符串中的“字符” ,hash[26]可以映射所有的字母。

情况2:(int)数据范围较小的时候

二、两数之和

. - 力扣(LeetCode)

解法2代码: 

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target)
    {
        unordered_map<int,int> hash; //数值和下标的映射关系
        int n=nums.size();
        for(int i=0;i<n;++i)
        {
            int x=target-nums[i];
            if(hash.count(x)) return {hash[x],i};
            hash[nums[i]]=i;
        }
        return {-1,-1};
    }
};

 三、判定是否互为字符重排

. - 力扣(LeetCode)

 解法2代码:

class Solution {
public:
    bool CheckPermutation(string s1, string s2) 
    {
        //小优化
        if(s1.size()!=s2.size()) return false;
        //用哈希表
        int hash[26]={0};
        for(char&ch:s1) ++hash[ch-'a'];
        //检测第二个数组
        for(char&ch:s2)  if(--hash[ch-'a']<0)  return false;
        return true;
    }
};

四、存在重复元素I

. - 力扣(LeetCode)

解法2代码:

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;
    }
};

 五、存在重复元素II

. - 力扣(LeetCode)

解法1代码:

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) 
    {
        unordered_map<int,size_t> hash;//数值和下标的映射
        size_t n=nums.size();
        for(size_t i=0;i<n;++i)
        {
            //如果哈希表中有这个数
            if(hash.count(nums[i])&&i-hash[nums[i]]<=k) return true;
            hash[nums[i]]=i;//存下标的映射
        }
        return false;
    }
};

解法2代码:

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
    //滑动窗口解题,让set始终保存着k个元素,如果发现了区间内有重复元素,那么就可以返回true
    unordered_set<int> s;
    size_t n=nums.size();
    for(size_t i=0;i<n;++i)
    {
        if(s.count(nums[i])) return true;
        s.emplace(nums[i]);//不断将数字丢进去
        if(i>=k) s.erase(nums[i-k]); //窗口超出区间了,就将最前面那个给删掉
    }
    return false;
    }
};

六、存在重复元素III(经典)

. - 力扣(LeetCode)

 解法1代码:

class Solution {
public:
    //绝对值尽量拆解掉
    //滑动窗口解决问题(控制区间)  需要支持插入、查找、删除  尽可能有序 set
    //k是下标的差值  t是元素的差值
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) 
    {
        //lower_bound 利用二分找到第一个>=num的迭代器 降序就是<=
        //upper_bound 利用二分找到第一个>num的迭代器  降序就是<
        set<long> s;//需要一个有序集合
        for(size_t i=0;i<nums.size();++i)
           { 
             //在下标范围为 [max(0,i−k),i] 内找到值范围在 [u−t,u+t]的数。
             set<long>::iterator it=s.lower_bound((long)nums[i]-t);
             if(it!=s.end()&&*it<=(long)nums[i]+t) return true;
             s.insert(nums[i]);
             if(i>=k)  s.erase(nums[i - k]);
           }
           return false;
    }
};

 思路2:分桶(非常精巧的思路)

思路来源:. - 力扣(LeetCode)分桶思路详细讲解

     因为这个思路来源写得非常的详细,所以直接看就行,以往我们的分桶,更多的是针对整数的分桶,但是在该题中,扩展了存在负数的时候如何分桶,保证每个桶内的元素个数是一样的。这是一种非常巧妙的方法!!!要结合具体的实例去看!!

核心思路:保证每个桶内的绝对值相差小于t,k个桶。当我们遍历到这个数的时候,如果对应的桶的存在,就是true,如果相邻桶存在,看看差值是否符合要求。每个桶中只会有一个元素,因为有多的我们就会直接返回结果。

class Solution {
public:
    int getid(long u,long t)
    {
        return u>=0?u/(t+1):(u+1)/(t+1)-1;
    }
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) 
    {
      //桶排序   
      size_t n=nums.size();
      //分成k个桶  每个桶的大小是t+1 (0,1,2,3) ->保证一个桶里面是符合的
      unordered_map<int,int> hash;  //第一个是存id  第二个是存元素
      for(size_t i=0;i<n;++i)
      {
        long u=nums[i];
        int id= getid(u,t); //找编号
        //看看当前桶存不存在
        if(hash.count(id)) return true;
        //看看相邻桶在不在,如果在的话 就看看差值
        if(  hash.count(id-1)&&u-hash[id-1]<=t
           ||hash.count(id+1)&&hash[id+1]-u<=t) return true;
        if(i>=k) hash.erase(getid(nums[i-k],t));//桶数多了,就去掉一个
        hash[id]=u;//开新的桶
      }
      return false;
    }
};

七、字母异位词分组(经典)

. - 力扣(LeetCode)

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        //字母异位词->排序后都是相同的
        unordered_map<string,vector<string>> hash; //将异位词绑定起来
        for(auto&s:strs)
         {
            string temp=s;
            sort(temp.begin(),temp.end());
            hash[temp].emplace_back(s);
         }
         //提取出来
         vector<vector<string>> ret;
         for(auto&[x,y]:hash)  ret.emplace_back(y); //取哈希表中键值对的方法C++14支持
         //for(auto&kv:hash)  ret.push_back(kv.second);
         return ret;
    }
};

八、前K个高频单词(经典)

 . - 力扣(LeetCode)

解法1:map+vector+稳定排序+lambda优化
          map的底层是红黑树,插入的时候map<string,int> 会按照字典序排好,而我们现在要按照出现次序去排序,同时对于出现次数相同的保证字典序在前面,所以我们其中之一的策略就是vector+sort ,但是sort底层是快排,并不具备稳定性,但是库里面有一个stable_sort是稳定的排序

class Solution {
public:
     typedef pair<string,int> PSI;
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        map<string,int> countmap;//计数
        for(auto&s:words) ++countmap[s];
        //此时已经按照字典序排好了,将其拷贝到vector中
        vector<PSI> nums(countmap.begin(),countmap.end());
        //要用一个稳定的排序 我们排序的是比较value,所以要修改比较逻辑
        stable_sort(nums.begin(),nums.end(),
        [](const PSI&kv1,const PSI&kv2) {return kv1.second>kv2.second;});
        vector<string> ret(k);
        for(int i=0;i<k;++i)  ret[i]=nums[i].first;
        return ret;
    }
};

解法2:unordered_map+vector+sort+调整比较逻辑+lambda优化 

class Solution {
public:
    typedef pair<string,int> PSI;
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        unordered_map<string,int> countmap;//计数
        for(auto&s:words) ++countmap[s];
        //此时已经按照字典序排好了,将其拷贝到vector中
        vector<PSI> nums(countmap.begin(),countmap.end());
        //要用一个稳定的排序 我们排序的是比较value,所以要修改比较逻辑
        sort(nums.begin(),nums.end(),
        [](const PSI&kv1,const PSI&kv2){ 
            return kv1.second>kv2.second||(kv1.second==kv2.second&&kv1.first<kv2.first);});
        vector<string> ret(k);
        for(int i=0;i<k;++i)  ret[i]=nums[i].first;
        return ret;
    }
};

上面两种解法都是借助vector容器+sort去解决的。

 解法3:unordered_map+priority_queue+compare类

class Solution {
public:
   typedef pair<string,int> PSI;
    struct compare//要注意仿函数要+const修饰,否则可能编译不过
     {
        bool operator()(const PSI&kv1,const PSI&kv2) const
        {
            if(kv1.second==kv2.second) return kv1.first<kv2.first;
            return kv1.second>kv2.second;
        }
     };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        unordered_map<string,int> countmap;//计数
        for(auto&s:words) ++countmap[s];
        //丢到优先级队列里
        priority_queue<PSI,vector<PSI>,compare> heap;
        for (auto& it : countmap) {
            heap.push(it);
            if (heap.size() > k) heap.pop();
        }
        vector<string> ret(k);
       for(int i=k-1;i>=0;--i) 
        {
            ret[i]=heap.top().first;
            heap.pop();
        }
       return ret;
    }
};

 解法4:unordered_map+multiset+compare类

class Solution {
public:
   typedef pair<string,int> PSI;
    struct compare//要注意仿函数要+const修饰,否则可能编译不过
     {
        bool operator()(const PSI&kv1,const PSI&kv2) const
        {
            return kv1.second>kv2.second||(kv1.second==kv2.second&&kv1.first<kv2.first);
        }
     };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        unordered_map<string,int> countmap;//计数
        for(auto&s:words) ++countmap[s];
        multiset<PSI,compare> sortmap(countmap.begin(),countmap.end());
        vector<string> ret(k);
        multiset<PSI,compare>::iterator it=sortmap.begin();
        size_t i=0;
        while(k--) 
        {
            ret[i++]=it->first;
            ++it;
        }
    return ret;
    }
};

 解法5:map+multimap+compare类(能过 但这是巧合)

       这题能过的原因是map实现了字典序的排序。而底层的multimap封装中对于相同的键值是优先插入到其右侧。

class Solution {
public:
     struct compare//要注意仿函数要+const修饰,否则可能编译不过
     {
        bool operator()(const int&k1,const int&k2) const
        {
            return k1>k2;
        }
     };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        map<string,int> countmap;//计数
        for(auto&s:words) ++countmap[s];
        multimap<int,string,compare> sortmap;
        for(auto &kv:countmap) sortmap.insert(make_pair(kv.second,kv.first));
        vector<string> ret(k);
        auto it=sortmap.begin();
        size_t i=0;
        while(k--) 
        {
            ret[i++]=it->second;
            ++it;
        }
    return ret;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1718597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】探索未来科技的前沿:人工智能、机器学习与大模型

文章目录 引言一、人工智能&#xff1a;从概念到现实1.1 人工智能的定义1.2 人工智能的发展历史1.3 人工智能的分类1.4 人工智能的应用 二、机器学习&#xff1a;人工智能的核心技术2.1 机器学习的定义2.2 机器学习的分类2.3 机器学习的实现原理2.4 机器学习的应用2.5 机器学习…

解锁 GPT-4o 背后数据带来的情绪价值

GPT-4o 可以说已经是一个富有情感、通人性的智能语音助手&#xff0c;或者更准确地说&#xff0c;是一个越来越接近人类交互的 “新物种”。这个强大的模型同时具备文本、图片、视频和语音理解和合成方面的能力&#xff0c;甚至可以被视为 GPT-5 的一个未完成版。 01 富有情感的…

【博客20】缤果Matlab串口调试助手V1.0(中级篇)

超级好用的Matlab串口调试助手 开发工具: MATLAB 2024a中文版 (编程语言matlab) -> Matlab APP Designer 目录 前言 一、软件概要&#xff1a; 二、软件界面&#xff1a; 1.App演示 ​ ​---- ◇♣♡♠ ---- 2.其他扩展App展示 ​编辑 三、获取 >> 源码以及G…

Android 图表开发开源库 MPAndroidChart 使用总结

1. 引言 电视项目中需要一个折线图表示节电数据变化情况&#xff0c;类比 H5 来说&#xff0c;Android 中也应该有比较成熟的控件&#xff0c;经过调研后&#xff0c;发现 MPAndroidChart 功能比较强大&#xff0c;网上也有人说可能是目前 Android 开发最好用的一个三方库了&a…

ChatGPT Edu版本来啦:支持GPT-4o、自定义GPT、数据分析等

5月31日&#xff0c;OpenAI在官网宣布&#xff0c;推出ChatGPT Edu版本。 据悉&#xff0c;这是一个专门为大学校园提供的ChatGTP&#xff0c;支持GPT-4o、网络搜索、自定义GPT、数据分析、代码生成等功能&#xff0c;可以极大提升学生、老师的学习质量和教学效率。 目前&…

算法-扫描线

目录 什么是扫描线算法&#xff1f; 扫描线简单应用 更多的扫描线 什么是扫描线算法&#xff1f; 在计算几何中&#xff0c;扫描线算法&#xff08;scan line algorithm&#xff09;一般用来解决几何图形的面积交并&#xff0c;周长交并问题&#xff0c;扫描线算法的核心思想…

AC/DC电源模块:应用于工业自动化领域

BOSHIDA AC/DC电源模块&#xff1a;应用于工业自动化领域 AC/DC电源模块是一种用来将交流电转换为直流电的电源模块。它在工业自动化领域有着广泛的应用&#xff0c;可以为各种设备和系统提供稳定可靠的电力供应。 一&#xff0c;AC/DC电源模块在工业自动化领域中起到了稳定…

洞察全球商机:精细化策略引领海外营销平台对接

随着全球市场的不断融合和互联网技术的飞速发展&#xff0c;企业越来越意识到海外营销与客服系统对接的重要性。 NetFarmer&#xff0c;作为一家专注于服务企业数字化出海的公司&#xff0c;对于海外市场的洞察和对接策略有着独特的见解。今天运营坛将深入探讨海外营销平台对接…

上市医疗巨头构建330+项自动化场景,实在Agent驱动效率与效益双重飞跃

历经二十年的快速发展&#xff0c;中国医疗信息化已迈入一个崭新阶段&#xff0c;其特征是产业链的高度集成、跨部门协同作业以及信息化的深度渗透。这一阶段不仅要求医护人员聚焦于以患者为中心的高质量服务&#xff0c;还提出了新挑战&#xff0c;即如何高效处理信息化系统伴…

Linux —— MySQL操作(1)

一、用户与权限管理 1.1 创建与赋予权限 create user peter% identified by 123465 # 创建用户 peter&#xff0c;# %&#xff1a;允许所有用户登录这个用户访问数据库 刚创建的新用户是什么权限都没有&#xff0c;需要赋予权限 grant select on mysql.* to peter%; # 赋予…

LeetCode2542最大子序列的分数

题目描述 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;两者长度都是 n &#xff0c;再给你一个正整数 k 。你必须从 nums1 中选一个长度为 k 的 子序列 对应的下标。 对于选择的下标 i0 &#xff0c;i1 &#xff0c;…&#xff0c; ik - 1 &#xff0c;你的 …

微信小程序区分运行环境

wx.getAccountInfoSync() 是微信小程序的一个 API&#xff0c;它可以同步获取当前账号信息。返回对象中包含小程序 AppID、插件的 AppID、小程序/插件版本等信息。 返回的对象结构如下&#xff1a; 小程序运行环境&#xff0c;可选值有&#xff1a;develop&#xff08;开发版&…

java实现地形dem产汇流流场数据提取解析

一、基础概念 在GIS和气象学、海洋学、大气科学、水文学等领域&#xff0c;"提取流场"通常指的是从数据集中识别和分析流体&#xff08;如水流、风场、洋流、大气流&#xff09;的运动模式和流向的过程。这个过程涉及数据处理、可视化和分析技术&#xff0c;下面是提…

【计算机网络】——概述(图文并茂)

概述 一.信息时代的计算机网络二.互联网概述1.网络&#xff0c;互连网&#xff0c;互联网&#xff08;因特网&#xff09;1.网络2.互连网3.互联网&#xff08;因特网&#xff09; 2.互联网简介1.互联网发展的三个阶段2.互联网服务提供者&#xff08;ISP&#xff09;3.互联网的组…

知了汇智携手川农大,为计算机学子打造实战型综合项目实训

随着数字化产业的迅猛发展和产业数字化转型的不断深入&#xff0c;产业对数字人才的需求也在发生变化。为了培养适应市场需求的高素质应用型人才&#xff0c;5月24日&#xff0c;知了汇智携手四川农业大学&#xff0c;为信息工程学院计算机科学与技术专业22级学子带来一场兼具实…

JDK JRE JVM 三者的关系

总结&#xff1a; 1. jdk 中 的 javac 编译器将 .java 文件编译为 .class 字节码文件 &#xff08;编译&#xff09; 2. jre 执行 .class 字节码文件 &#xff08;运行&#xff09; 3. jre 通过 jvm 运行程序&#xff0c;确保程序能够在不同平台上正确执行&#xff08;实现跨平…

Operation not allowed when innodb_forced_recovery > 0.

到mysql的配置文件中 把这行注释掉

第N3周:Pytorch文本分类入门

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 这里借用K同学的一张图片大致说明本次任务流程。 1.本次所用AG News数据集介绍 AG…

医院内跌倒的预测模型构建(Boruta+lightgbm+DCA分析)

医院内跌倒的预测模型构建&#xff08;BorutalightgbmDCA分析&#xff09; 跌倒有时候是很严重的事情&#xff0c;常常听说骨质疏松的老年人跌倒后造成髋骨骨折&#xff0c;导致长期卧床&#xff0c;进而导致肌肉萎缩、肺炎等等并发症&#xff0c;最终导致不良预后。医院内的跌…

AWS中国峰会2024 半日游

亚马逊云科技中国峰会于2024年5月29-30日在上海举办 今年就去了半天&#xff0c;去年也是去过的&#xff0c;不过今年的活动个人感觉比去年略微凌乱了一点。 今年的峰会方向和去年一致&#xff0c;均是AI方向的各项内容&#xff08;基础架构、安全、服务、游戏、驾驶、各行各…