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

​​​【收录 Hello 算法】10.4 哈希优化策略

目录

10.4   哈希优化策略

10.4.1   线性查找:以时间换空间

10.4.2   哈希查找:以空间换时间


10.4   哈希优化策略

在算法题中,我们常通过将线性查找替换为哈希查找来降低算法的时间复杂度。我们借助一个算法题来加深理解。

Question

给定一个整数数组 nums 和一个目标元素 target ,请在数组中搜索“和”为 target 的两个元素,并返回它们的数组索引。返回任意一个解即可。

10.4.1   线性查找:以时间换空间

考虑直接遍历所有可能的组合。如图 10-9 所示,我们开启一个两层循环,在每轮中判断两个整数的和是否为 target ,若是,则返回它们的索引。

线性查找求解两数之和

图 10-9   线性查找求解两数之和

代码如下所示:

two_sum.c

/* 方法一:暴力枚举 */
int *twoSumBruteForce(int *nums, int numsSize, int target, int *returnSize) {for (int i = 0; i < numsSize; ++i) {for (int j = i + 1; j < numsSize; ++j) {if (nums[i] + nums[j] == target) {int *res = malloc(sizeof(int) * 2);res[0] = i, res[1] = j;*returnSize = 2;return res;}}}*returnSize = 0;return NULL;
}

此方法的时间复杂度为 𝑂(𝑛2) ,空间复杂度为 𝑂(1) ,在大数据量下非常耗时。

10.4.2   哈希查找:以空间换时间

考虑借助一个哈希表,键值对分别为数组元素和元素索引。循环遍历数组,每轮执行图 10-10 所示的步骤。

  1. 判断数字 target - nums[i] 是否在哈希表中,若是,则直接返回这两个元素的索引。
  2. 将键值对 nums[i] 和索引 i 添加进哈希表。

<1><2><3>

two_sum_hashtable_step3

图 10-10   辅助哈希表求解两数之和

实现代码如下所示,仅需单层循环即可:

two_sum.c

/* 哈希表 */
typedef struct {int key;int val;UT_hash_handle hh; // 基于 uthash.h 实现
} HashTable;/* 哈希表查询 */
HashTable *find(HashTable *h, int key) {HashTable *tmp;HASH_FIND_INT(h, &key, tmp);return tmp;
}/* 哈希表元素插入 */
void insert(HashTable *h, int key, int val) {HashTable *t = find(h, key);if (t == NULL) {HashTable *tmp = malloc(sizeof(HashTable));tmp->key = key, tmp->val = val;HASH_ADD_INT(h, key, tmp);} else {t->val = val;}
}/* 方法二:辅助哈希表 */
int *twoSumHashTable(int *nums, int numsSize, int target, int *returnSize) {HashTable *hashtable = NULL;for (int i = 0; i < numsSize; i++) {HashTable *t = find(hashtable, target - nums[i]);if (t != NULL) {int *res = malloc(sizeof(int) * 2);res[0] = t->val, res[1] = i;*returnSize = 2;return res;}insert(hashtable, nums[i], i);}*returnSize = 0;return NULL;
}

此方法通过哈希查找将时间复杂度从 𝑂(𝑛2) 降至 𝑂(𝑛) ,大幅提升运行效率。

由于需要维护一个额外的哈希表,因此空间复杂度为 𝑂(𝑛) 。尽管如此,该方法的整体时空效率更为均衡,因此它是本题的最优解法

相关文章:

  • C#屏蔽基类成员
  • 【MySQL】库的基础操作
  • v-rep--lua接口和c++接口的关联
  • Docker自定义镜像
  • 探索未来直播新纪元:Voodoo Spatial 的3D 直播革命
  • Java顺序表
  • web4.0-元宇宙虚拟现实
  • CCF-GESP 等级考试 2023年12月认证C++一级真题
  • JavaScript Window对象
  • 如何让大模型更聪明?提升AI智能的关键策略
  • Cocos Creator 编辑器的数据绑定详解
  • C#同花顺下单 模拟操作版接口实现
  • 【Qt 学习笔记】Qt窗口 | 菜单栏 | QMenuBar的使用及说明
  • Python怎样将PDF拆分成多个文件
  • 对gRPC中常见的 grpc::CreateChannel()这个类所创建的对象所包含的属性做详细介绍
  • 【刷算法】从上往下打印二叉树
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • 78. Subsets
  • co模块的前端实现
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • REST架构的思考
  • sessionStorage和localStorage
  • 复杂数据处理
  • 讲清楚之javascript作用域
  • 经典排序算法及其 Java 实现
  • 前端面试题总结
  • 全栈开发——Linux
  • 推荐一个React的管理后台框架
  • 自定义函数
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​什么是bug?bug的源头在哪里?
  • $NOIp2018$劝退记
  • (二)构建dubbo分布式平台-平台功能导图
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (五)IO流之ByteArrayInput/OutputStream
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转)linux下的时间函数使用
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET Framework杂记
  • .NET MAUI Sqlite数据库操作(二)异步初始化方法
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .Net Redis的秒杀Dome和异步执行
  • @Data注解的作用
  • @RequestMapping用法详解
  • @RunWith注解作用
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • [AX]AX2012 SSRS报表Drill through action
  • [DevEpxress]GridControl 显示Gif动画
  • [IOI2018] werewolf 狼人
  • [javaSE] GUI(Action事件)
  • [Matlab有限元分析] 2.杆单元有限元分析