当前位置: 首页 > news >正文

数据结构(五):哈希表及面试常考的算法

一、哈希表介绍

1、定义

哈希表,也叫散列表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。例如,下列键(key)为人名,value为性别。

2、常用的哈希结构

数组

map(映射)

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可以重复key不可以修改O(logn)O(logn)
std::multimap红黑树key有序key可以重复key不可以修改O(logn)O(logn)
std::unordered_map哈希表key无序key不可以重复key不可以修改O(1)O(1)

set(集合)

集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::set红黑树有序O(logn)O(logn)
std::multiset红黑树有序O(logn)O(logn)
std::unordered_set哈希表无序O(1)O(1)

2、优缺点及使用场景

优点:高效的查找和插入操作、适用于大数据量、灵活性、快速的删除操作

缺点:空间消耗、不适合有序数据、哈希冲突、依赖好的哈希函数

使用场景:快速查找需求、缓存实现、消除重复元素、分布式系统

3、决定哈希表结构的性能的三个因素:

哈希函数、哈希表的大小、碰撞处理方法。

4、基本操作

数据存储:假设我们需要存储5个元素,首先使用哈希函数(Hash)计算Joe的键,也就是字符串‘Joe’的哈希值,得到4928,然后将哈希值除以数组长度5(mod运算),求得其余数。因此,我们将Joe的数据存进数组的3号箱子中。

冲突:如果两个哈希值取余的结果相同,我们称这种情况为‘冲突’。假设Nell键的哈希值为6276,mod 5的结果为1。但此时1号箱已经存储了Sue的数据,可使用链表在已有的数据的后面继续存储新的数据。(本方法为链地址法,还有几种解决冲突的方法。其中,应用较为广泛的是“开放地址法”)。

查询:假设最终的哈希表为

如果要查找Ally的性别,首先算出Alley键的哈希值,然后对它进行mod运算。最终结果为3。

然而3号箱中数据的键是Joe而不是Ally。此时便需要对Joe所在的链表进行线性查找。找到了键为Ally的数据。取出其对应的值,便知道了Ally的性别为女(F)。 

二、面试常考的算法

1、在数组中查找对称键值对

题目:给定一个整数对数组,找到所有对称对,即相互镜像的对。

示例:

Input:  {3, 4}, {1, 2}, {5, 2}, {7, 10}, {4, 3}, {2, 5}
Output:{4, 3} | {3, 4} ,{2, 5} | {5, 2}

思路:使用一个哈希表map,将数组中第一个元素作为键,第二个元素作为值。遍历数组中的每对元素,对于每对元素,检查反向对是否已经存在于哈希表中。如果存在,说明找到了对称键值对,否则,将当前对插入到哈希表中。

map.find(2)  //查找key为2的键值对是否存在 ,若没找到则返回map.end()。

map.end()   //指向哈希表的最后一个容器,实则超出了哈希表的范围,为空。

#include<iostream>
#include<map>
#include<unordered_map>
using namespace std;// 查找对称键值对
void has_symmetric_pair(pair<int, int> intPairArray[], int length){unordered_map<int, int> map;for(int i = 0; i < length; i++){int key = intPairArray[i].first;int value = intPairArray[i].second;// 检查反向对是否存在于哈希表中 if (map.find(value) != map.end() && map[value] == key){cout << "对称键值对有:(" << key <<", " << value<< ")|" <<"(" << value << ", " <<key <<")\n";}// 将当前对插入哈希表map[key] = value;}
}int main() {// 创建一个整数对数组pair<int, int> intPairArray[6];int length = 6;// 分别给数组的元素赋值intPairArray[0] = make_pair(1, 2);intPairArray[1] = make_pair(3, 4);intPairArray[2] = make_pair(5, 6);intPairArray[3] = make_pair(7, 8);intPairArray[4] = make_pair(6, 5);intPairArray[5] = make_pair(4, 3);// 访问数组的元素for (int i = 0; i < 6; ++i) {std::cout << "Element " << i << ": (" << intPairArray[i].first << ", " << intPairArray[i].second << ")\n";}has_symmetric_pair(intPairArray, length);return 0;
}

2、追踪遍历的完整路径

题目:使用哈希实现树的遍历路径,输出每个叶子节点的路径。

示例:input:给定一颗树

           output:Node 4 Path: 1 -> 2 -> 4 ->

                         Node 5 Path: 1 -> 2 -> 5 ->

                         Node 3 Path: 1 -> 3 ->

思路:在DFS的先序遍历中,逐步构建路径,当遇到叶子节点时,将该节点和对应的路径存储在哈希表中。最后,遍历哈希表输出结果。

#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};unordered_map<TreeNode*, vector<int>> pathMap; void dfs(TreeNode* node, vector<int>& path) {if (node == nullptr) return;path.push_back(node->val);if (node->left == nullptr && node->right == nullptr) {pathMap[node] = path; } else {dfs(node->left, path);dfs(node->right, path);}path.pop_back(); 
}int main() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);vector<int> path;dfs(root, path);for (auto pair : pathMap) {cout << "Node " << pair.first->val << " Path: ";for (int val : pair.second) {cout << val << " -> ";}cout << endl;}delete root->left->right;delete root->left->left;delete root->left;delete root->right;delete root;return 0;
}

3、查找数组是否是另一个数组的子集

题目:输入两个数组,如果数组1是数组2的元素,则返回True,否则返回False。

示例:input:数组1[3,2,4],数组2[1,2,3,4,5,8]     output:数组1是数组2的子集

思路:先将两个数组转换为 set,然后通过遍历第一个集合,检查其中的每个元素是否也在第二个集合中。

if(set2.find(num) != set2.end())   //判断找到了key为2的键值对

#include<set>
#include<iostream>
using namespace std;bool isSubSet(int nums1[], int nums2[], int length1, int length2){set<int> set1, set2;// int length1 = sizeof(nums1) / sizeof(nums1[0]);// int length2 = sizeof(nums2) / sizeof(nums2[0]);for(int i = 0; i < length1; i++){set1.insert(nums1[i]);}for(int j = 0; j < length2; j++){set2.insert(nums2[j]);}for(int num: set1){if(set2.find(num) == set2.end()){return false;}}return true;
}int main(){int nums1[] = {3, 2, 4};int nums2[] = {1, 2, 3, 4, 5, 8};int length1 = sizeof(nums1) / sizeof(nums1[0]);int length2 = sizeof(nums2) / sizeof(nums2[0]);bool result = isSubSet(nums1,nums2, length1, length2);if (result) {cout << "arr1 is a subset of arr2" << std::endl;} else {cout << "arr1 is not a subset of arr2" << std::endl;}}

 

4、检查给定的数组是否不相交

题目:输入两个数组,如果数组1与数组2相交,则返回True,否则返回False。

示例:input:数组1[9],数组2[3,2]     output:数组1与数组2不相交。

思路:先将两个数组转换为set,然后使用set_intersection 函数找到它们的交集。如果交集为空,则数组不相交。

std::set_intersection 是 C++ 标准库 <algorithm> 头文件中的一个函数,它用于求两个已排序容器(比如集合或数组)的交集。

函数声明如下:

template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first);

  • first1, last1: 第一个容器的起始和结束迭代器。
  • first2, last2: 第二个容器的起始和结束迭代器。
  • d_first: 结果输出的目标容器的起始迭代器。
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
bool areDisjoint(int arr1[], int arr2[], int length1, int length2){set<int> set1, set2;for(int i = 0; i < length1; i++){set1.insert(arr1[i]);}for(int j = 0; j < length2; j++){set2.insert(arr2[j]);}// 同检查数组是否是另一个数组的子集// for(auto c: set1){//     if(set2.find(c) != set2.end()){//         return true;//     }// }// return false;// 利用集合的交集来求set<int> intersection;set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), inserter(intersection, intersection.begin()));if (intersection.empty()){return false;}return true;
}int main(){int arr1[] = {9};int arr2[] = {3, 2};int length1 = sizeof(arr1) / sizeof(arr1[0]);int length2 = sizeof(arr2) / sizeof(arr2[0]);bool res = areDisjoint(arr1, arr2, length1, length2);if (res){cout << "arr1与arr2相交";}else{cout << "arr1与arr2不相交";}
}

 

 

相关文章:

数据结构(五):哈希表及面试常考的算法

一、哈希表介绍 1、定义 哈希表&#xff0c;也叫散列表&#xff0c;是根据关键码和值 (key和value) 直接进行访问的数据结构&#xff0c;通过key和value来映射到集合中的一个位置&#xff0c;这样就可以很快找到集合中的对应元素。例如&#xff0c;下列键(key)为人名&#xf…...

水利部加快推进小型水库除险加固,大坝安全监测是重点

国务院常务会议明确到2025年前&#xff0c;完成新出现病险水库的除险加固&#xff0c;配套完善重点小型水库雨水情和安全监测设施&#xff0c;实现水库安全鉴定和除险加固常态化。 为加快推进小型水库除险加固前期工作&#xff0c;水利部协调财政部提前下达了2023年度中央补助…...

实施电子采购的6个有效步骤

耗时又费力&#xff0c;手动采购之苦相信大家都受够了&#xff0c;现在越来越多的企业正在实施电子采购策略。根据CIPS的《2022年采购与供应数字化报告》&#xff0c;多达95%的企业在采购与供应商管理中采用了技术。 但采用技术并不能保证立竿见影的效果。企业需要制定好电子采…...

【Shell脚本6】Shell 运算符

Shell 基本运算符 Shell 和其他编程语言一样&#xff0c;支持多种运算符&#xff0c;包括&#xff1a; 算术运算符关系运算符布尔运算符逻辑运算符字符串运算符文件测试运算符 原生bash不支持简单的数学运算&#xff0c;但是可以通过其他命令来实现&#xff0c;例如 awk 和 …...

设计模式之保护性暂停

文章目录 1. 定义2. 实现保护性暂停模式3. Join原理4. 保护性暂停模式的扩展 1. 定义 即Guarded Suspension&#xff0c;用在一个线程等待另一个线程的执行结果。 有一个结果需要从一个线程传递给另一个线程&#xff0c;让他们关联到同一个GuarderObject&#xff08;这就是保…...

UE5、CesiumForUnreal实现加载GeoJson绘制单面(Polygon)功能(StaticMesh方式)

文章目录 1.实现目标2.实现过程2.1 实现原理2.1.1 数据读取2.1.2 三角剖分2.1.3 创建StaticMesh2.2 应用测试2.2.1 具体代码2.2.2 蓝图应用测试3.参考资料1.实现目标 通过读取本地GeoJson数据,在UE中以StaticMeshComponent的形式绘制出面数据,支持Editor和Runtime环境,GIF动…...

Linux 下以其他用户运行程序

需求&#xff1a; 在root的用户下&#xff0c;设置开启自启&#xff0c;这些服务都要用一个swadmin用户运行。 1、创建需要执行的命令脚本 vim /usr/local/bin/start_services.sh#!/bin/bash runuser -l swadmin -c cd /opt/server/ && ./service.sh start s-app-ser…...

Centos7下安装使用K3S

## K3S简介 K3S官方文档链接 K3s是一个轻量级的、专为容器化应用和Kubernetes集群设计的开源Kubernetes发行版。K3s的目标是提供一个更小、更简单、更易于部署和维护的Kubernetes集群。它是Rancher Labs开发的一个项目&#xff0c;旨在满足边缘计算、IoT设备、开发和测试环境…...

易云维®工厂能耗管理平台系统方案,保证运营质量,推动广东制造企业节能减排

我国《关于完整准确全面贯彻新发展理念推进碳达峰碳中和工作的实施意见》出台&#xff0c;提出了推进碳达峰碳中和工作的总体目标。到2025年&#xff0c;广东具备条件的地区、行业和企业率先实现碳达峰&#xff0c;为全省实现碳达峰、碳中和奠定坚实基础&#xff1b;2030年前实…...

Qwt QwtWheel绘制滚动轮

1.简介 QwtWheel 是一个用于实现滚动轮控件的类库。它基于 Qt 框架&#xff0c;并提供了一些方便的功能来处理滚动轮的事件和绘图。 QwtWheel 类继承自 QWidget类&#xff0c;用于定义滚动轮控件的通用行为。QwtWheel 添加了特定于滚动轮的功能。 QwtWheel 可以用于创建具有滚…...

【C++语法讲解】 | 运算符重构 | 三种运算符的重构方式 |代码演示

文章目录 1&#xff0c;简述2&#xff0c;结构体的定义1&#xff0c;结构体的声明2&#xff0c;结构体的申请 3.1 &#xff0c;在结构体中重构3.2 在结构体外进行重构 1&#xff0c;简述 通常情况下&#xff0c;我们会创建一些简单的数据结构以应对日常的算法使用&#xff0c;…...

[100天算法】-寻找峰值(day 63)

题目描述 峰值元素是指其值大于左右相邻值的元素。给定一个输入数组 nums&#xff0c;其中 nums[i] ≠ nums[i1]&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个峰值所在位置即可。你可以假设 nums[-1] nums[n…...

Go语言开发环境安装,hello world!

1. Go开发包SDK https://golang.google.cn/dl/&#xff08;国内也可以安装&#xff09; 根据自己电脑下载对应的安装包&#xff0c;我懒下载了msi安装 然后一路点确定安装Go 2.安装GoLand https://www.jetbrains.com/go/download/#sectionwindows 下载安装包 一路确定安装完…...

记CVE-2022-39227-Python-JWT漏洞

文章目录 前言影响版本漏洞分析Newstar2023 Week5总结 前言 在Asal1n师傅的随口一说之下&#xff0c;说newstar week5出了一道祥云杯一样的CVE&#xff0c;于是自己也是跑去看了一下&#xff0c;确实是自己不知道的一个CVE漏洞&#xff0c;于是就从这道题学习到了python-jwt库…...

软件测试/测试开发丨如何利用ChatGPT自动生成测试用例思维导图

点此获取更多相关资料 简介 思维导图是一种用图形方式表示思维和概念之间关系的工具&#xff1a; 有些公司会使用思维导图编写测试用例&#xff0c;这样做的优点是&#xff1a; 1.可视化和结构化。 2.易于理解&#xff0c;提高效率。 而 ChatGPT 是无法直接生成 xmind 格式…...

【编程语言发展史】Unity开发语言的历史发展

Unity开发前期版本时&#xff0c;使用的是一种名为UnityScript的类似JavaScript的语言。然而&#xff0c;随着时间的推移&#xff0c;开发者社区大多数人都倾向于使用C#进行开发&#xff0c;Unity决定将重点放在C#上&#xff0c;因为C#具有更强大的生态系统、更好的性能和更广泛…...

springboot http添加请求头 添加请求证书

首先明确两个事情&#xff1a;请求对象&#xff0c;连接对象 我们知道你要是想发起一个请求&#xff0c;需要指定两个环节内容&#xff0c;一个是请求内容对象(request)&#xff0c;一个是连接内容对象(httpClient) 它们两个的作用我们在下面会看到 简要分析源码 1.先说一下…...

【Qt之数据库操作】

使用Qt实现SQLite数据库操作可以分为以下几个步骤&#xff1a; 添加SQLite头文件和库文件&#xff1a; 在Qt项目中&#xff0c;需要在.pro文件中添加以下内容&#xff1a; QT sql打开/创建数据库&#xff1a; 可以使用QSqlDatabase类中的静态函数addDatabase()来添加数据库…...

数据结构(c语言版) 队列

链队列 要求&#xff1a;实现链队列的创建、初始化、入队、出队 &#xff08;先进先出&#xff09; 代码 // // Created by My.cy on 2023/10/19. // //链队列 创建、初始化、入队、出队 先进先出#include <stdio.h> #include <malloc.h>//定义结构体 struct…...

kimera论文阅读

文章目录 功能构成&#xff1a;Kimera线程A. Kimera-VIO:B. Kimera-RPGO:C. Kimera-Mesher:D. Kimera-Semantics:E.调试工具 功能构成&#xff1a; Kimera包括四个关键模块: Kimera-VIO的核心是基于gtsam的VIO方法[45]&#xff0c;使用IMUpreintegration和无结构视觉因子[27]…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...