【算法日志】哈希表应用:set和map容器,哈希表的使用(day5)

2023-11-18

代码随想录60day

【链表】day4                                             【链表】day3


目录

前言

一、三种哈希结构

数组

散列技术(哈希思想)

哈希碰撞

set(集合)

map(映射)

二、哈希表的一些应用

总结



前言

哈希表(也叫散列表)是一种较为常用的数据结构,我们常用的数组其实就是一种简单的哈希表。而本文将介绍哈希思想,哈希法实现的三种哈希结构以及哈希表的一些应用。


一、三种哈希结构

在我们使用哈希表时,通常需要从信息中提取出“key”和"value"这两个信息。

比如上图,如果我们要查询学生的中文名字时,可以将学号作为所谓的“key”,然后将学号下对应的中文名字视作"value",通过“key”查找“value”所形成的这么一组信息被称为键值对。当然,作为"key"的不一定是数字,我们也可以将学生的英文名字作为“key”。key的取值不定,往往根据查找信息而确立。

那么我们确立好键值对后该怎么对数据进行储存呢?我们一般会使用如下三种数据结构:

·数组               ·set(集合)               ·map(映射)

数组

我们可以将数组的角标作为key,然后中文名字作为数组的值,这样我们可以通过数组角标查值,完成以键查值的操作。但问题是,我们的数组角标都是1,2,3......这样较小的数字,如果使用1021这样,甚至更大的数字作为角标,毫无疑问会造成内存浪费。如果我们使用学生的英文名字作为“key”,甚至都不能作为数组角标。那么我们应该如何解决这个问题呢?

散列技术(哈希思想)

当我们的key值为一些较大的或者不太规律的数字时,我们可以通过对数字进行适当运算来,来将其转化为可适用的角标。以1021为例,我们可以将其减去1020以获得适当的角标。而当我们的key值为一些字母时,可以计算其与首字母的位置。这样的方法也被称为散列技术。

例1

class Solution
{
public:
    int numJewelsInStones(string jewels, string stones) 
    {
        int hash1[26];
        int hash2[26];
        int sum = 0;

        for (int i = 0; i < jewels.length(); i++) 
        {
            if (jewels[i] >= 'A' && jewels[i] <= 'Z') 
            {
                hash1[jewels[i] - 'A']++;
            }
            else 
            {
                hash2[jewels[i] - 'a']++;
            }
        }
     
        for (int i = 0; i < stones.length(); i++) 
        {
            if (stones[i] >= 'A' && stones[i]<= 'Z') 
            {
                if (hash1[stones[i] - 'A'] != 0) 
                {
                    sum++;
                }
            }
            else
            {
                if (hash2[stones[i] - 'a'] != 0)
                {
                    sum++;
                }
            }
        }

        return sum;
    }
};

 该例题就利用了散列技术,将字母转化为合适的key值,并利用该key值进行查找。

哈希碰撞

如果张三和李四都喜欢“john"这个名字,那么如果将英文名字作为key值,就会造成key值重复,这就是所谓的哈希碰撞。

那么我们如何解决这样的"这样的碰撞”呢?以下有两种解决方案。

·拉链法


 直接将冲突元素作为链表节点连接冲突角标后。

·线性探测法

哈希表5

 将冲突元素放置下一个空位,这种方法一定要保证tableSize要大于dataSize。

set(集合)

 map(映射)

 这两种数据结构属于STL库中的内容,我们只需要掌握其使用方法即可,不需要深究其内部实现。

二、哈希表的一些应用

例2

    bool isAnagramMap(string s, string t)
    {

        unordered_map<char,int> map;
        if (s.length() != t.length())
            return false;
        for (int i = 0; i < s.length(); i++)
        {
            auto iter = map.find(s[i]);
            if (iter != map.end())
                iter->second++;
            map.insert(pair<char,int>(s[i],1));
        }
        for (int j = 0; j < t.length(); j++)
        {
            auto iter = map.find(t[j]);
            if (iter != map.end() && iter->second > 0)
                iter->second--;
            else
                return false;
        }
        return true;
    }
    bool isAnagramArray(char* s, char* t)
    {
        int i, x[26] = { 0 }, y[26] = { 0 };
        for (i = 0; s[i] != '\0'; i++)	x[s[i] - 'a']++;	
        for (i = 0; t[i] != '\0'; i++)	y[t[i] - 'a']++;	
        for (i = 0; i < 26; i++)							
            if (x[i] != y[i])	return false;
        return true;										
    }

 例3

   vector<int> twoSum(vector<int>& nums, int target)
    {
        unordered_map<int, int>map1,map2;
        for (int i = 0; i < nums.size(); i++)
        {
            auto iter = map2.find(nums[i]);
            if (iter != map2.end())
                iter->second++;
            map1.insert(pair<int, int>(nums[i], i));
            map2.insert(pair<int, int>(nums[i], 1));
        }

        for (int i = 0; i < nums.size(); i++)
        {
            auto iter1 = map1.find(target - nums[i]);
            auto iter2 = map2.find(target - nums[i]);
            if (iter1 != map1.end())
            {
                if (i == iter1->second || (iter2->second == 1 &&
                nums[i] == iter1->first))
                    continue;
                return { i,iter1->second };
            }
        }
        return {};
    }

例4

总结

以上就是今天要讲的内容,本文仅仅简单介绍了哈希表的使用,而使用好哈希结构和哈希思想对于于解决和优化一些问题有重要作用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法日志】哈希表应用:set和map容器,哈希表的使用(day5) 的相关文章

  • 金特 + XNA (C#)

    是否可以使用jint http jint codeplex com操作使用 XNA C 创建的 3D 环境 并向该环境添加功能 再次使用 jint 作为 Jint 的贡献者 我会推荐你Jint http jint codeplex com
  • 我应该把 try/catch 和“using”语句放在哪里? [复制]

    这个问题在这里已经有答案了 可能的重复 try catch using 正确的语法 https stackoverflow com questions 4590490 try catch using right syntax 我想try c
  • 是否可以从 C++ 应用程序调用 C# 应用程序?

    我是一名编程学生 现在我已经上了两门 C 课程 这个学期我将参加我的第一门 C 课程 出于好奇 是否可以从 C 应用程序调用 C 应用程序 如果是的话 是否还可以检查运行该程序的计算机是否具有 NET框架 我只是很好奇 我想如果可能的话 这
  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • IEnumerable 的 String.Join(string, string[]) 的类似物

    class String包含非常有用的方法 String Join string string 它从数组创建一个字符串 用给定的符号分隔数组的每个元素 但一般来说 它不会在最后一个元素之后添加分隔符 我将它用于 ASP NET 编码 以用
  • 锁定 ASP.NET 应用程序变量

    我在 ASP NET 应用程序中使用第三方 Web 服务 对第 3 方 Web 服务的调用必须同步 但 ASP NET 显然是多线程的 并且可能会发出多个页面请求 从而导致对第 3 方 Web 服务的同时调用 对 Web 服务的调用封装在自
  • C free() 是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 malloc 和 free 如何工作 https stackoverflow com questions 1119134 how malloc and free work include
  • XPATH 查询、HtmlAgilityPack 和提取文本

    我一直在尝试从名为 tim new 的类中提取链接 我也得到了解决方案 给出了解决方案 片段和必要的信息here https stackoverflow com questions 2982862 extracting a table ro
  • 异常堆栈跟踪不显示抛出异常的位置

    通常 当我抛出异常 捕获它并打印出堆栈跟踪时 我会看到抛出异常的调用 导致该异常的调用 导致该异常的调用that 依此类推回到整个程序的根 现在它只向我显示异常所在的调用caught 而不是它所在的地方thrown 我不明白是什么改变导致了
  • 将下拉列表与字典绑定

    我将字典绑定到下拉列表 举例来说 我的字典中有以下项目 Test1 123 Test2 321 我希望下拉文本采用以下格式 Test1 Count 123 Test2 Count 321 我沿着以下路径走 但没有运气 MyDropDown
  • 全局使用和 .NET Standard 2.0

    我最近意识到我可以使用 C 10 功能文件范围的命名空间在 NET Standard 2 0 项目中也可以通过设置
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • 在 C# 中何时使用 ArrayList 而不是 array[]?

    我经常使用一个ArrayList而不是 正常 array 当我使用时 我感觉好像我在作弊 或懒惰 ArrayList 什么时候可以使用ArrayList在数组上 数组是强类型的 并且可以很好地用作参数 如果您知道集合的长度并且它是固定的 则
  • 时间:2019-03-17 标签:c++fstream并发访问

    如果从不同的进程 线程同时访问文件会发生什么 据我所知 没有锁定文件的标准方法 只有操作系统特定的功能 就我而言 文件将被经常读取而很少写入 现在如果A打开一个文件进行读取 ifstream 并开始读取块 和B打开相同的文件进行写入 ofs
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 使用 OleDbCommandBuilder 时访问 SQL 语法错误

    我要在 C 中使用 OleDbDataAdapter 在 Access 数据库中插入数据 但收到错误消息INSERT INTO 命令中的语法错误 BackgroundWorker worker new BackgroundWorker Ol
  • 无法在 C# 中为 EventArgs 分配使用派生类型的事件处理程序

    所以我有一个事件声明如下 public event EventHandler OnChangeDetected 然后我有以下处理程序被分配给该事件 myObject OnChangeDetected OnTableChanged 我的理解是
  • 如何在dll级别读取app.config? [复制]

    这个问题在这里已经有答案了 我在一个解决方案中有一个控制台应用程序项目和库项目 dll The 图书馆项目有 app config 文件 我在其中存储我在库中使用的一些键值对 控制台应用程序引用此 dll 我有另一个 app config
  • 如果“嵌入式”SQL 2008 数据库文件不存在,如何创建它?

    我使用 C ADO Net 和在 Server Management Studio 中创建的嵌入式 MS SQL 2008 数据库文件 附加到 MS SQL 2008 Express 创建了一个数据库应用程序 有人可以向我指出一个资源 该资
  • 如何提高环复杂度?

    对于具有大量决策语句 包括 if while for 语句 的方法 循环复杂度会很高 那么我们该如何改进呢 我正在处理一个大项目 我应该减少 CC gt 10 的方法的 CC 并且有很多方法都存在这个问题 下面我将列出一些例如我遇到的问题的

随机推荐