做网站打广告/靠谱的免费建站

做网站打广告,靠谱的免费建站,河北斯皮尔网站建设,经营性质的网站两数之和 问题描述示例提示思路分析代码实现代码解析1. 哈希表结构体定义2. 初始化哈希表3. 释放哈希表内存4. 主函数 twoSum5. 返回结果复杂度分析 第二种解法代码功能概述代码详细注释1. 哈希表结构体定义2. 哈希表指针3. 查找函数4. 插入函数5. 两数之和函数 6. 主函数&…

两数之和

    • 问题描述
    • 示例
    • 提示
    • 思路分析
    • 代码实现
    • 代码解析
      • 1. 哈希表结构体定义
      • 2. 初始化哈希表
      • 3. 释放哈希表内存
      • 4. 主函数 `twoSum`
      • 5. 返回结果
      • 复杂度分析
    • 第二种解法
      • 代码功能概述
      • 代码详细注释
        • 1. 哈希表结构体定义
        • 2. 哈希表指针
        • 3. 查找函数
        • 4. 插入函数
        • 5. 两数之和函数
      • 6. 主函数(示例)
      • 总结

问题描述

给定一个整数数组 nums 和一个整数 target,你需要在数组中找出两个数,它们的和为目标值 target。返回这两个数的数组下标。每个输入只会有一个有效答案,并且你不能使用相同的元素两次。

示例

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9,返回 [0, 1]。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示

  • 2 <= nums.length <= 10^4
  • -10^9 <= nums[i] <= 10^9
  • -10^9 <= target <= 10^9
  • 只会存在一个有效答案

思路分析

这个问题可以通过哈希表来高效地解决。具体思路如下:

  1. 创建一个哈希表,存储已经遍历过的数和它们对应的索引。
  2. 对于每个数,计算 target 减去当前数的差值,即 complement
  3. 如果差值 complement 在哈希表中已经存在,则找到了符合条件的两个数,直接返回它们的下标。
  4. 如果差值不在哈希表中,则将当前数加入哈希表。

通过哈希表的查找特性,我们可以在一次遍历中完成求解,时间复杂度为 O(n),空间复杂度为 O(n)。

代码实现

#include <stdio.h>
#include <stdlib.h>typedef struct { int* table; // 哈希表数组int size;   // 哈希表大小
} HashTable;// 初始化哈希表
void initHash(HashTable* hashTable, int size) {hashTable->size = size;hashTable->table = (int*)malloc(size * sizeof(int));  // 分配内存for (int i = 0; i < size; i++) {hashTable->table[i] = -1;  // 初始化哈希表中的值为-1,表示没有存储任何数据}
}// 释放哈希表内存
void freeHash(HashTable* hashTable) { free(hashTable->table);  // 释放哈希表中的数组内存free(hashTable);  // 释放哈希表结构体内存
}// 查找和为目标值的两个数的下标
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {int size = 20001;  // 哈希表的大小,范围[-10^9, 10^9]需要加上10000进行偏移,保证索引为正HashTable* hashTable = (HashTable*)malloc(sizeof(HashTable)); // 分配哈希表结构体内存initHash(hashTable, size);  // 初始化哈希表for (int i = 0; i < numsSize; i++) {// 计算当前数的补数int complement = target - nums[i];int index = complement + 10000;  // 补数的哈希表索引,偏移+10000确保索引为正// 如果补数已经在哈希表中,说明找到了两个数,它们的和等于目标值if (hashTable->table[index] != -1) {int* result = (int*)malloc(2 * sizeof(int));  // 分配结果数组result[0] = i;  // 当前数的下标result[1] = hashTable->table[index];  // 补数的下标freeHash(hashTable);  // 释放哈希表内存*returnSize = 2;  // 设置返回结果的大小return result;  // 返回结果}// 如果补数不在哈希表中,将当前数添加到哈希表int numIndex = nums[i] + 10000;  // 当前数的哈希表索引hashTable->table[numIndex] = i;  // 将当前数的下标存入哈希表}freeHash(hashTable);  // 释放哈希表内存*returnSize = 0;  // 没有找到结果,返回0return NULL;  // 返回空值
}

代码解析

1. 哈希表结构体定义

我们定义了一个 HashTable 结构体,它包含两个成员:

  • table:一个数组,用于存储哈希表中的数据。我们使用一个整数数组,哈希表的大小为 20001,以适应数据范围 [-10^9, 10^9],通过加上 10000 来保证索引为正。
  • size:哈希表的大小。

2. 初始化哈希表

initHash 函数中,我们为哈希表分配内存,并将哈希表中的所有值初始化为 -1,表示该位置还没有存储数据。

3. 释放哈希表内存

freeHash 函数中,我们释放了哈希表的内存,包括哈希表的数组和结构体本身。

4. 主函数 twoSum

  • 我们首先计算目标值 target 和当前数的差值 complement
  • 通过偏移量 10000 将补数的范围映射到哈希表的索引范围内,确保索引为正。
  • 如果哈希表中已经存在补数,则返回当前数和补数的下标。
  • 如果哈希表中不存在补数,则将当前数及其下标存入哈希表。

5. 返回结果

  • 如果找到了符合条件的两个数,我们将它们的下标存入一个结果数组并返回。
  • 如果没有找到符合条件的数对,返回 NULL

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组 nums 的长度。我们只需要遍历一次数组,每次操作的时间复杂度为 O(1)(哈希表查找和插入操作)。
  • 空间复杂度:O(n),我们需要一个哈希表来存储最多 n 个元素。
    可惜,这种解法需要空间过大,无法满足所有案例。

第二种解法

// 定义哈希表的结构体
struct hashTable {int key;                  // 哈希表的键,用于存储数值int val;                  // 哈希表的值,用于存储索引UT_hash_handle hh;        // UT_hash库提供的宏,用于处理哈希表操作
};// 声明一个全局指针,用于指向哈希表的头节点
struct hashTable* hashtable;// 查找哈希表中是否存在某个键
struct hashTable* find(int ikey) {struct hashTable* tmp;                        // 定义一个临时指针用于存储查找结果HASH_FIND_INT(hashtable, &ikey, tmp);         // 使用UT_hash库提供的宏查找键为ikey的元素return tmp;                                   // 返回查找结果
}// 向哈希表中插入键值对
void insert(int ikey, int ival) {struct hashTable* it = find(ikey);            // 首先查找键是否已存在if (it == NULL) {                             // 如果键不存在struct hashTable* tmp = malloc(sizeof(struct hashTable)); // 分配内存tmp->key = ikey, tmp->val = ival;         // 初始化键值对HASH_ADD_INT(hashtable, key, tmp);        // 使用UT_hash库提供的宏将新元素添加到哈希表中} else {                                      // 如果键已存在it->val = ival;                           // 更新值}
}// 解决“两数之和”问题
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {hashtable = NULL;                             // 初始化哈希表为空for (int i = 0; i < numsSize; i++) {          // 遍历数组struct hashTable* it = find(target - nums[i]); // 查找当前元素的补数是否在哈希表中if (it != NULL) {                         // 如果找到补数int* ret = malloc(sizeof(int) * 2);   // 分配内存用于存储结果ret[0] = it->val, ret[1] = i;         // 存储两个数的索引*returnSize = 2;                      // 设置返回结果的大小为2return ret;                           // 返回结果}insert(nums[i], i);                       // 将当前元素及其索引插入哈希表}*returnSize = 0;                              // 如果未找到结果,设置返回结果的大小为0return NULL;                                  // 返回NULL
}作者:力扣官方题解
链接:https://leetcode.cn/problems/two-sum/solutions/434597/liang-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

官方解法虽然看着复杂,实际上最重要的是多了#include “uthash.h”,自己得学会如何调库。

代码功能概述

这段代码使用了UTHash库来实现“两数之和”问题。目标是在给定数组中找到两个数,它们的和等于目标值 target,并返回这两个数的索引。

代码详细注释

1. 哈希表结构体定义
struct hashTable {int key;          // 键:存储数组中的数值int val;          // 值:存储数组中数值对应的索引UT_hash_handle hh; // UTHash宏定义的句柄,用于内部管理哈希表节点
};
  • key:哈希表的键,用于存储数组中的数值。
  • val:哈希表的值,用于存储数组中数值对应的索引。
  • UT_hash_handle hh:这是UTHash库要求的字段,用于管理哈希表的内部结构(例如,存储链表指针、哈希值等)。用户不需要直接操作这个字段。
2. 哈希表指针
struct hashTable* hashtable;
  • 这是一个全局变量,指向哈希表的根节点。UTHash库通过这个指针来管理整个哈希表。
3. 查找函数
struct hashTable* find(int ikey) {struct hashTable* tmp;HASH_FIND_INT(hashtable, &ikey, tmp); // 使用UTHash宏查找键为ikey的节点return tmp; // 返回找到的节点,如果未找到则返回NULL
}
  • HASH_FIND_INT:这是UTHash库提供的宏,用于在哈希表中查找键为 ikey 的节点。
    • 第一个参数是哈希表的根节点指针(hashtable)。
    • 第二个参数是指向键值的指针(&ikey)。注意,这里传入的是键值的地址。
    • 第三个参数是输出参数,用于存储查找结果。
  • 如果找到键为 ikey 的节点,则返回该节点;否则返回 NULL
4. 插入函数
void insert(int ikey, int ival) {struct hashTable* it = find(ikey); // 先查找键是否已存在if (it == NULL) { // 如果键不存在struct hashTable* tmp = malloc(sizeof(struct hashTable)); // 分配新节点tmp->key = ikey, tmp->val = ival; // 初始化新节点的键和值HASH_ADD_INT(hashtable, key, tmp); // 使用UTHash宏将新节点插入哈希表} else { // 如果键已存在it->val = ival; // 更新节点的值}
}
  • HASH_ADD_INT:这是UTHash库提供的宏,用于将一个新节点插入哈希表。
    • 第一个参数是哈希表的根节点指针(hashtable)。
    • 第二个参数是哈希表结构体中用于哈希的字段名(key)。
    • 第三个参数是要插入的新节点(tmp)。
  • 如果键已存在,则更新该键对应的值。
5. 两数之和函数
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {hashtable = NULL; // 初始化哈希表为空for (int i = 0; i < numsSize; i++) {struct hashTable* it = find(target - nums[i]); // 查找补数是否已存在if (it != NULL) { // 如果找到补数int* ret = malloc(sizeof(int) * 2); // 分配返回数组ret[0] = it->val, ret[1] = i; // 返回补数的索引和当前索引*returnSize = 2; // 设置返回数组的大小return ret; // 返回结果}insert(nums[i], i); // 将当前数值及其索引插入哈希表}*returnSize = 0; // 如果未找到结果,返回大小为0return NULL; // 返回NULL
}
  • 逻辑流程
    1. 初始化哈希表:将 hashtable 设置为 NULL,表示哈希表为空。
    2. 遍历数组
      • 对于数组中的每个数字 nums[i],计算它的补数(target - nums[i])。
      • 使用 find 函数查找补数是否已经在哈希表中。
      • 如果找到补数:
        • 分配一个大小为2的数组 ret,存储补数的索引和当前索引。
        • 设置返回数组的大小为2。
        • 返回结果。
      • 如果未找到补数:
        • 调用 insert 函数,将当前数字及其索引插入哈希表。
    3. 未找到结果
      • 如果遍历结束后仍未找到结果,设置返回大小为0,并返回 NULL

6. 主函数(示例)

int main() {int nums[] = {2, 7, 11, 15}; // 输入数组int target = 9;              // 目标值int returnSize;              // 返回结果的大小int* result = twoSum(nums, 4, target, &returnSize); // 调用两数之和函数if (result) { // 如果找到结果printf("Result: [%d, %d]\n", result[0], result[1]); // 打印结果free(result); // 释放结果内存} else { // 如果未找到结果printf("No solution found.\n");}return 0;
}
  • 输出
    Result: [0, 1]
    
  • 解释
    • 数组 [2, 7, 11, 15] 中,nums[0] + nums[1] = 2 + 7 = 9,因此返回 [0, 1]

总结

这段代码通过UTHash库实现了“两数之和”问题,具有以下优点:

  1. 动态哈希表:UTHash库可以动态管理哈希表,适合处理大范围的整数。
  2. 简洁高效:UTHash提供了简洁的宏来操作哈希表,代码易于理解和维护。
  3. 时间复杂度低:哈希表操作的时间复杂度为O(1),整体算法时间复杂度为O(n)。

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

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

相关文章

2025年SCI1区TOP:真菌生长优化算法FGO,深度解析+性能实测

目录 1.摘要2.算法原理3.结果展示4.参考文献5.代码获取 1.摘要 本文提出了一种新型的自然启发元启发式算法——真菌生长优化算法&#xff08;FGO&#xff09;&#xff0c;灵感来源于真菌在自然界中的生长行为。真菌的生长行为包括菌丝生长、分枝和孢子萌发&#xff0c;菌丝生长…

1 | 从零开始解密数据库:数据库基础概念

❤个人主页&#xff1a;折枝寄北的博客 ❤专栏位置&#xff1a;数据库专栏 目录 前言1. 数据&#xff08;data&#xff09;2. 数据库(DB)3. 数据库管理系统(DBMS)4. 数据库系统(DBS) 感谢您的阅读支持 前言 【前言】 在万物互联的数字时代&#xff0c;数据已成为驱动社会运转…

Web自动化之Selenium下Chrome与Edge的Webdriver常用Options参数

目录 引言 说明 Add_argument() 添加方式 常用参数 Add_experimental_option() 添加方式 常用方法 任务结束后仍然保持浏览器打开 禁用“Chrome 正受到自动测试软件的控制”提示 设置下载路径 禁用弹窗拦截 禁用图片加载 禁用 JavaScript 注意 引言 …

AI提示词的种类与适合的任务

以下是提示词的主要种类及其适用任务&#xff0c;基于大模型特性与最佳实践总结&#xff1a; 一、基础提示词 零样本提示&#xff08;Zero-shot Prompting&#xff09; 形式&#xff1a;直接输入任务指令&#xff0c;不提供示例&#xff08;如“翻译以下句子&#xff1a;Hello …

FTP 实验(ENSP模拟器实现)

目录 FTP 概述 FTP实验 FTP的报文交互 FTP 概述 FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是一种用于在网络上进行文件传输的标准协议。它允许用户在两台计算机之间上传和下载文件。 1、FTP采用客户端-服务器模型&#xff0c;客户端通过…

Windows前端开发IDE选型全攻略

Windows前端开发IDE选型全攻略 一、核心IDE对比矩阵 工具名称最新版本核心优势适用场景推荐指数引用来源VS Code2.3.5轻量级/海量插件/跨平台/Git深度集成全栈开发/中小型项目⭐⭐⭐⭐⭐14WebStorm2025.1智能提示/框架深度支持/企业级调试工具大型项目/专业前端团队⭐⭐⭐⭐47…

鸿蒙5.0实战案例:har和hsp的转换

往期推文全新看点&#xff08;文中附带全新鸿蒙5.0全栈学习笔录&#xff09; ✏️ 鸿蒙&#xff08;HarmonyOS&#xff09;北向开发知识点记录~ ✏️ 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ ✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景&#…

SAP-ABAP:使用ST05(SQL Trace)追踪结构字段来源的步骤

ST05 是 SAP 提供的 SQL 跟踪工具&#xff0c;可以记录程序运行期间所有数据库操作&#xff08;如 SELECT、UPDATE、INSERT&#xff09;。通过分析跟踪结果&#xff0c;可以精准定位程序中结构字段对应的数据库表。 步骤1&#xff1a;激活ST05跟踪 事务码 ST05 → 点击 Activa…

【落羽的落羽 数据结构篇】树、二叉树

文章目录 一、树1. 树的概念和结构2. 树的相关术语 二、二叉树1. 概念与结构2. 满二叉树3. 完全二叉树4. 二叉树的性质5. 二叉树的存储结构 一、树 1. 树的概念和结构 之前我们学习了线性表&#xff0c;今天我们再来接触一种全新的数据结构——树。 树是一种非线性的数据结构…

CPU、MCU、MPU、SOC、DSP、ECU、GPU、FPGA傻傻分不清楚?一文讲清它们的区别

文章目录 前言一、定义与功能1、CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09;2、MCU&#xff08;Microcontroller Unit&#xff0c;微控制单元&#xff09;3、MPU&#xff08;Microprocessor Unit&#xff0c;微处理器&#xff09;4、SOC&#x…

网络安全学习-常见安全漏洞检测以及修复方法-1

渗*透测试 渗透测试就是模拟攻击者入侵系统&#xff0c;对系统进行一步步渗透&#xff0c;发现系统的脆弱环节和隐藏风险。形成测试报告提供给系统的所有者&#xff0c;所有者根据报告对系统进行加固&#xff0c;提升系统的安全性&#xff0c;防止真正的攻击者入侵。 渗透测试…

JVM之JVM的组成

Java 虚拟机&#xff08;JVM&#xff09;是 Java 程序的运行核心&#xff0c;它主要由类加载系统、运行时数据区、执行引擎和本地方法接口这几个关键部分组成。 类加载系统&#xff08;Class Loading System&#xff09; 类加载系统负责在程序运行时动态地将 Java 类加载到 J…

个人简历html网页模板,科技感炫酷html简历模板

炫酷动效登录页 引言 在网页设计中,按钮是用户交互的重要元素之一。这样一款黑色个人简历html网页模板,科技感炫酷html简历模板,设计效果类似科技看板图,可帮您展示技能、任职经历、作品等,喜欢这种风格的小伙伴不要犹豫哦。该素材呈现了数据符号排版显示出人形的动画效…

java后端开发day18--学生管理系统

&#xff08;以下内容全部来自上述课程&#xff09; 1.业务分析并搭建主菜单 1.需求 采取控制台的方式去书写学生管理系统 2.分析 1.初始菜单 2.学生类 属性&#xff1a;id&#xff0c;姓名&#xff0c;年龄&#xff0c;家庭住址 3.添加功能 键盘录入每一个学生信息并…

记录一次部署PC端网址全过程

当我查看我之前写的文章时、顿时惊奇发出感慨&#xff1a;啥时候写的&#xff1f;是我写的么&#xff1f;疑惑重重… 所以说&#xff0c;好记性不如烂笔头。 记录一次部署PC端网址全过程 部署PC端网址分是三步&#xff1a;第一步&#xff1a;申请域名并映射到外网IP &#xff0…

本地大模型编程实战(22)用langchain实现基于SQL数据构建问答系统(1)

使 LLM(大语言模型) 系统能够查询结构化数据与非结构化文本数据在性质上可能不同。后者通常生成可在向量数据库中搜索的文本&#xff0c;而结构化数据的方法通常是让 LLM 编写和执行 DSL&#xff08;例如 SQL&#xff09;中的查询。 我们将演练在使用基于 langchain 链 &#x…

最好的Git实践指南(Windows/Linux双系统详解)

Git最佳实践指南&#xff1a;从入门到熟练&#xff08;Windows/Linux双系统详解&#xff09; 一、环境搭建与基础配置&#xff08;适用Windows/Linux&#xff09; 1.1 Git安装与验证 # Windows系统安装&#xff08;推荐Chocolatey包管理&#xff09; # 直接下载git二进制文件…

Python零基础学习第二天(条件语句,循环语句)

Python零基础学习第二天&#xff1a;流程控制与模块导入 一、流程控制结构 1. 条件语句&#xff08;if, elif, else&#xff09; 条件语句用于根据不同的条件执行不同的代码块。基本形式如下&#xff1a; if 条件1: # 当条件1为True时执行这里的代码 elif 条件2: # 当前面的条…

从零开始用react + tailwindcs + express + mongodb实现一个聊天程序(三) 实现注册 登录接口

1.划分文件夹 在src目录下创建controllers middleware models routes controllers 放具体的方法 signup login middleware 里面是中间件 请求的验证 models 放对象实体 routes 处理访问路径像/signup /login 等等 2. 接口开发 系统的主要 有用户认证 和 消息 2种类型…

MOE结构解读和deepseek的MoE结构

不管dense还是MoE&#xff08;Mixture of Experts&#xff09;都是基于transformer的。 下面回顾下解码器块的主要架构&#xff1a; 注意力机制-层归一化&残差连接-FFN前馈神经网络-层归一化&残差连接。 dense模型是沿用了这个一架构&#xff0c;将post-norm换为pre-no…