【Leetcode刷题随笔】01. 两数之和

1. 题目描述

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

2. 解法分析

2.1 解法1:双循环

容易想到使用双层for循环来枚举答案的暴力方法解决此问题,但是效率太低下,O(n²)时间复杂度,不适合大数据量

该方法过程如下:

  1. 构建循环
  • 外层循环变量i从0到numsSize-1

  • 内层循环变量ji+1numsSize-1(确保不会重复使用同一个元素)

  1. 检查数对和:

if(nums[i] + nums[j] == target)
  • 如果找到满足条件的数对,执行以下操作:

  • 设置返回大小*returnSize = 2

  • 动态分配结果数组(两个int)

  • 将两个索引存入数组:result[0]=i, result[1]=j

  • 直接返回结果数组

  1. 未找到解的处理:
  • 设置*returnSize = 0

  • 返回NULL

时间复杂度

  • O(n²): 最坏情况下需要检查所有n(n-1)/2个数对

空间复杂度

  • O(1): 除结果数组外只使用常数空间(结果数组不计入空间复杂度时)
  1. 无解处理:
  • 设置*returnSize=0并返回NULL是标准做法

  • 调用者可通过returnSize判断是否有解

示例执行过程

输入:nums = [2,7,11,15], target=9

  1. i=0 (值2), j=1 (值7): 2+7=9 → 找到解

  2. 分配结果数组,设置result[0]=0, result[1]=1

  3. 设置*returnSize=2

  4. 返回结果数组[0,1]

2.2 解法二:哈希表

当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。我们首先将所有元素遍历一遍存放到哈希表中,第二次遍历的时候就去哈希表中查询是否有已经遍历过的数和当前遍历的数相加是否等于target。

哈希表版本解题思路:

步骤1:定义哈希表结构

  • 使用结构体map构造哈希表的条目,包含:

      key: 数组元素的值value: 该元素在数组中的索引
    

步骤2:实现哈希表基本操作

  • hashMapAdd: 添加或更新键值对。如果键不存在,创建新条目并添加到哈希表;如果存在,则更新其值。

  • hashMapFind: 根据键查找条目,返回条目指针(找不到返回NULL)。

  • hashMapCleanUp: 清理哈希表,释放所有条目内存。

步骤3:实现twoSum函数

a. 初始化全局哈希表指针为NULL(避免之前的数据干扰)。

b. 预分配结果数组ans(两个整数)。

c. 第一次遍历数组:将每个元素的值作为key,索引作为value存入哈希表。

注意:如果遇到相同的元素,后面的索引会覆盖前面的(因为同一个key在哈希表中只能存在一个)。

d. 第二次遍历数组:对于每个元素nums[i],计算补数complement = target - nums[i],然后在哈希表中查找补数。

查找成功且满足条件(补数对应的索引不等于当前索引,避免同一个元素用两次)时:

将当前索引i和补数的索引hashMapRes->value存入结果数组。

设置返回数组大小为2,返回结果数组。

e. 如果遍历结束未找到,则清理哈希表并返回NULL。

优势:
哈希表版本的核心思路是“空间换时间”,通过O(n)的额外空间将时间复杂度从O(n²)降低到O(n)。它通过两次遍历完成:

第一次遍历:建立值到索引的映射(哈希表)。

第二次遍历:对于每个元素,检查其补数是否在哈希表中(且不是自身)。

与双层循环法相比,哈希表法更适合处理大规模数据,但需要注意内存泄漏和线程安全问题。

3. C语言代码实现

3.1 双层for循环法

int* twoSum(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){*returnSize = 2;int* result = (int*)malloc(2 * sizeof(int));result[0] = i;result[1] = j;return result;}}}*returnSize = 0;return NULL;
}

3.2 哈希表法

typedef struct
{int key;int value;UT_hash_handle hh;
}map;map* hashMap = NULL;void hashMapAdd(int key, int value){map* s;//检查key是否在hash表中HASH_FIND_INT(hashMap, &key, s);if(s == NULL){s = (map*)malloc(sizeof(map));s->key = key;HASH_ADD_INT(hashMap, key, s);}s->value = value;
}map* hashMapFind(int key){map* s;HASH_FIND_INT(hashMap, &key, s);return s;
}void hashMapCleanUp(){map* cur, *tmp;HASH_ITER(hh, hashMap, cur, tmp){HASH_DEL(hashMap, cur);free(cur);}
}void hashPrint(){map* s;for(s = hashMap; s != NULL; s = (map*)(s -> hh.next)){printf("key = %d, value = %d", s->key, s->value);}
}int* twoSum(int* nums, int numsSize, int target, int* returnSize){int i, *ans;//在哈希表里寻找补数map* hashMapRes;hashMap = NULL;ans = malloc(sizeof(int) * 2);for(i = 0; i < numsSize; i++){//key代表nums[i]的值,value代表所在indexhashMapAdd(nums[i], i);}for(i = 0; i < numsSize; i++){hashMapRes = hashMapFind(target - nums[i]);if(hashMapRes && hashMapRes -> value != i){ans[0] = i;ans[1] = hashMapRes -> value;*returnSize = 2;return ans;}}hashMapCleanUp();return NULL;
}

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

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

相关文章

【机器学习深度学习】多层神经网络的构成

目录 一、神经网络模型的结构化组成方式 1. 最底层&#xff1a;神经网络模型 (Model) 2. 中间层&#xff1a;单个神经网络层 (Layer) 3. 最顶层&#xff1a;训练参数的细节 (Parameters & Variables) 二、关键理解要点 三、类比理解 场景一&#xff1a;工厂运作 场…

设计模式:揭秘Java原型模式——让复杂对象的创建不再复杂

原型模式 原型模式介绍 定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 西游记中的孙悟空&#xff0c;拔毛变小猴&#xff0c;孙悟空这种根据自己的形状复制出多个身外化身的技巧&…

Go语言-文件操作

基本介绍 文件是数据源&#xff0c;数据库也是一种特殊的文件。 Go语言中os.File结构体封装了文件的相关操作。 打开和关闭文件 -----打开文件----- file, err : os.Open("D:/111.txt") if err ! nil{fmt.Println("err ", err) }此时file就是一个指针&…

【电力物联网】云–边协同介绍

(꒪ꇴ꒪ )&#xff0c;Hello&#xff0c;我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的技术…

《深入解析 C#(第 4 版)》推荐

《深入解析 C#&#xff08;第 4 版&#xff09;》推荐 在 C# 语言不断演进的技术浪潮中&#xff0c;《深入解析 C#&#xff08;第 4 版&#xff09;》犹如一座灯塔&#xff0c;为开发者照亮探索的道路。无论是经验丰富的老程序员&#xff0c;还是初入 C# 领域的新手&#xff0c…

【网络】Linux 内核优化实战 - net.core.netdev_max_backlog

目录 Linux 内核参数 net.core.netdev_max_backlog 详解一、参数概述二、参数功能与作用2.1 核心功能2.2 网络数据包处理流程 三、查看当前参数值3.1 通过 sysctl 命令3.2 直接读取 /proc/sys 文件 四、修改参数值4.1 临时修改&#xff08;立即生效&#xff0c;重启后失效&…

Nuitka 打包Python程序

文章目录 Nuitka 打包Python程序&#x1f680; **一、Nuitka 核心优势**⚙️ **二、环境准备&#xff08;Windows 示例&#xff09;**&#x1f4e6; **三、基础打包命令****单文件脚本打包****带第三方库的项目** &#x1f6e0;️ **四、高级配置选项****示例&#xff1a;完整命…

自动获取文件的内存大小怎么设置?批量获取文件名和内存大小到Excel中的方法

在对重要数据进行备份或迁移操作前&#xff0c;为确保备份全面无遗漏&#xff0c;且合理规划目标存储设备的空间&#xff0c;会将文件名和内存提取到 Excel。比如&#xff0c;某个部门要将旧电脑中的文件迁移到新服务器&#xff0c;提前整理文件信息&#xff0c;能清晰知道所需…

创建型设计模式——单例模式

单例设计模式 什么是创建型设计模式有哪些创建型设计模式 单例设计模式实现方法饿汉式单例懒汉式单例实现方法 CSDN——C单例模式详解 单例设计模式是一种创建型设计模式 什么是创建型设计模式 创建型设计模式&#xff0c;就是通过控制对象的创建方式来解决设计问题。 有哪…

html 照片环 - 图片的动态3D环绕

html 照片环 - 图片的动态3D环绕 引言一、源码二、图转base64参考链接 引言 效果展示&#xff1a; 一、源码 原始图片的base64编码字符太多了&#xff0c;博客放不下&#xff0c;将图片缩小后的加入html的源码如下&#xff1a; <!DOCTYPE html> <html><hea…

ADIOS2 介绍与使用指南

文章目录 ADIOS2 介绍与使用指南什么是ADIOS2?ADIOS2 的主要特点ADIOS2 核心概念ADIOS2 安装Linux 系统安装Windows 安装 ADIOS2 基本使用C 示例Python 示例 ADIOS2 高级特性并行I/O流模式 ADIOS2 引擎类型性能优化建议总结 ADIOS2 介绍与使用指南 什么是ADIOS2? ADIOS2(Ad…

网络安全 vs 信息安全的本质解析:数据盾牌与网络防线的辩证关系关系

在数字化生存的今天&#xff0c;每一次手机支付、每一份云端文档、每一条医疗记录的背后&#xff0c;都矗立着这两座安全堡垒。理解它们的协同逻辑&#xff0c;不仅是技术从业者的必修课&#xff0c;更是企业构建数字防护体系的底层认知 —— 毕竟当勒索软件同时切断 "护城…

ping-pong操作

常见不匹配的原因 瞬时数据率的差异&#xff1b; 数据顺序的差异&#xff1b; 对比维度PipelineFIFOPing-Pong逻辑复制结构类型时序分级推进&#xff08;寄存器链&#xff09;环形队列&#xff08;缓冲区&#xff09;双缓冲区&#xff08;轮换使用&#xff09;功能块并行&am…

21.合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 思路&#xff1a;这里使用的主要数据结构是单链表。该算法采用经典的双指针技术来合并列表。 A dummy node is created; this node does not hold any meaningful value b…

vue3中简单易懂说明nextTick的使用

nextTick(): 等待下一次 DOM 更新刷新的工具方法 重点解释: 当你在 Vue 中更改响应式状态时&#xff0c;最终的 DOM 更新并不是同步生效的&#xff0c;而是由 Vue 将它们缓存在一个队列中&#xff0c;直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变…

gRPC 相关介绍

介绍 依赖两大技术 HTTP/2 作为传输协议 gRPC 底层用 HTTP/2&#xff0c;它支持&#xff1a; 多路复用&#xff08;在一条 TCP 连接中并行传输多个请求和响应&#xff09;二进制传输&#xff08;更紧凑、高效&#xff09;流式传输&#xff08;客户端流、服务端流、双向流&…

PyTorch 模型镜像下载与安装指南

在国内&#xff0c;由于网络限制&#xff0c;直接从 PyTorch 官方源下载可能会遇到速度慢或无法访问的问题。为了解决这一问题&#xff0c;可以使用国内镜像源来加速下载和安装 PyTorch。 文章目录 安装指定版本的 PyTorch&#xff08;以 CUDA 11.8 为例&#xff09;安装 CPU 版…

2025年SVN学习价值分析

⚖️ 一、SVN的现状与应用场景分析 仍在特定领域发挥作用 传统企业维护场景&#xff1a;在金融、电信、政府等采用集中式开发流程的机构中&#xff0c;许多遗留系统仍使用SVN管理。这些系统往往体量庞大、架构稳定&#xff0c;迁移成本高&#xff0c;因此SVN短期内不会被完全替…

JavaScript中的10种排序算法:从入门到精通

作为前端开发者&#xff0c;排序算法是我们必须掌握的基础知识。无论是在面试中&#xff0c;还是在实际开发中处理数据展示时&#xff0c;排序都是一个常见需求。今天&#xff0c;我将用通俗易懂的方式&#xff0c;带你了解JavaScript中最常见的10种排序算法。 1. 冒泡排序 - …

【微信小程序】6、SpringBoot整合WxJava获取用户手机号

1、手机号快速验证组件 手机号快速验证组件 旨在帮助开发者向用户发起手机号申请&#xff0c;并且必须经过用户同意后&#xff0c;开发者才可获得由平台验证后的手机号&#xff0c;进而为用户提供相应服务。 该能力与手机号实时验证组件的区别为&#xff1a; 手机号快速验证…