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

力扣1. 两数之和

定一个整数数组 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 <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

1.暴力求解

class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {int n = nums.size();for (int i = 0; i < n; ++i){for (int j = i + 1; j < n; ++j){if(nums[i] + nums[j] == target){return {i,j};}}}return {};}
};

1. 函数定义与参数

vector<int> twoSum(vector<int>& nums, int target)
  • 作用:接收一个整数数组 nums 和目标值 target,返回一个包含两个下标的数组(这两个下标对应的元素之和为 target)。
  • vector<int>& nums:输入的数组(& 表示引用传递,避免复制数组的开销)。
  • int target:需要达成的目标和。
  • 返回值 vector<int>:存储两个符合条件的元素下标。

2. 获取数组长度

int n = nums.size();
  • 先获取数组 nums 的长度 n(元素个数),避免在循环中多次调用 nums.size()(提升微小效率)。

3. 外层循环(遍历第一个元素)

for (int i = 0; i < n; ++i)
  • i 是第一个元素的下标,从 0 遍历到 n-1(覆盖数组中所有元素)。
  • 作用:逐个选取数组中的元素作为 “第一个候选元素”(nums[i])。

4. 内层循环(遍历第二个元素)

for (int j = i + 1; j < n; ++j)
  • j 是第二个元素的下标,从 i + 1 开始遍历到 n-1
  • 关键逻辑:j 从 i + 1 开始,是为了避免重复检查同一对元素(比如 i=0, j=1 和 i=1, j=0 是同一对元素,无需重复判断),同时确保 i ≠ j(同一个元素不能用两次)。
  • 作用:为每个 nums[i] 匹配它后面的所有元素作为 “第二个候选元素”(nums[j])。

5. 判断和是否等于目标值

if(nums[i] + nums[j] == target)
  • 检查当前两个候选元素的和是否等于 target
  • 如果满足条件,直接返回这两个元素的下标 {i, j}(因为题目保证 “有且仅有一个解”,找到后可立即返回)。

6. 兜底返回(语法兼容)

return {};
  • 题目明确说明 “输入一定存在唯一解”,因此这个语句实际不会被执行。
  • 作用:保证函数在语法上完整(C++ 要求函数必须有返回值)。

核心特点总结

  • 优点:逻辑简单直接,容易理解,不需要额外的存储空间。
  • 缺点:时间复杂度高,为 O(n²)n 是数组长度),因为外层循环执行 n 次,内层循环平均执行 n/2 次,总操作次数约为 n²/2
  • 适用场景:适合理解问题逻辑,或处理数据量很小的情况;大数据量时推荐用哈希表解法(时间复杂度 O(n))。

2.哈希表

class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {// 哈希表:键为数组元素值,值为对应下标unordered_map<int, int> numMap;// 遍历数组for (int i = 0; i < nums.size(); ++i) {// 计算当前元素的“补数”(目标值 - 当前元素)int complement = target - nums[i];// 若补数存在于哈希表中,说明找到符合条件的两个数if (numMap.find(complement) != numMap.end()) {return {numMap[complement], i};}// 若补数不存在,将当前元素和下标存入哈希表numMap[nums[i]] = i;}// 题目保证有解,此处仅为语法兼容return {};}
};

代码逐行解释

1. 函数定义

vector<int> twoSum(vector<int>& nums, int target) {
  • 这是函数的声明:返回值是 vector<int>(存储两个下标),函数名是 twoSum,参数有两个:nums 是输入的整数数组(引用传递,避免拷贝开销),target 是目标和。

2. 哈希表定义

unordered_map<int, int> numMap;
  • unordered_map 是 C++ 中的哈希表容器,这里定义了一个名为 numMap 的哈希表。
  • 哈希表的键(key) 是 int 类型,存储数组中已经遍历过的元素的值;
  • 哈希表的值(value) 是 int 类型,存储该元素在数组中的下标。
  • 作用:通过哈希表快速记录 “已遍历元素的值” 和 “其下标” 的对应关系,后续查找时可以直接通过 “值” 定位到 “下标”,时间复杂度为 O (1)(比数组遍历查找的 O (n) 快很多)。

3. 遍历数组

for (int i = 0; i < nums.size(); ++i) {
  • 用 for 循环遍历整个数组 numsi 是当前遍历到的元素的下标(从 0 开始)。
  • 遍历的目的:逐个处理数组中的每个元素,检查是否存在另一个已遍历的元素,与当前元素的和等于 target

4. 计算 “补数”

int complement = target - nums[i];
  • nums[i] 是当前遍历到的元素的值。
  • complement 翻译为 “补数”,指的是:如果存在一个数 x,使得 nums[i] + x = target,那么 x 就等于 target - nums[i],也就是这里的 complement
  • 例如:如果 target 是 9,当前 nums[i] 是 2,那么 complement 就是 7(因为 2 + 7 = 9)。我们需要检查之前是否遍历过 7。

5. 检查补数是否已存在于哈希表中

if (numMap.find(complement) != numMap.end()) {
  • numMap.find(complement):在哈希表中查找 “键为 complement” 的元素。如果找到,返回该元素的迭代器(类似指针);如果没找到,返回 numMap.end()(哈希表的 “结束标记”)。
  • 条件 numMap.find(complement) != numMap.end() 的意思是:补数 complement 存在于哈希表中(即之前已经遍历过值为 complement 的元素)。
  • 此时说明:当前元素 nums[i] 和哈希表中记录的 complement 对应的元素,它们的和就是 target,这两个元素就是我们要找的解。

6. 返回结果

  • 如果上一步的条件成立,直接返回一个包含两个下标的数组:
    • numMap[complement]:哈希表中 “键为 complement” 对应的值,也就是之前遍历过的 complement 元素的下标;
    • i:当前元素 nums[i] 的下标。
  • 这两个下标对应的元素之和为 target,因此是正确结果。

7. 补数不存在时,将当前元素存入哈希表

numMap[nums[i]] = i;

8. 兜底返回(语法兼容)

  • 题目明确说明 “输入数组中一定存在唯一解”,因此这个 return 语句实际上永远不会被执行。
  • 它的作用是保证函数在语法上完整(C++ 要求函数必须有返回值)。

核心逻辑总结

  1. 用哈希表记录 “已遍历元素的值 → 下标” 的映射,实现快速查找;
  2. 遍历每个元素时,计算它的 “补数”(需要和它相加得 target 的数);
  3. 检查补数是否已在哈希表中(即是否已遍历过):
    • 若是,直接返回两个元素的下标;
    • 若否,将当前元素存入哈希表,继续遍历。

为什么这样高效?

  • 时间复杂度:O (n)(n 是数组长度)。每个元素只遍历一次,哈希表的查找和插入操作都是 O (1);
  • 空间复杂度:O (n)。最坏情况下,需要将数组中所有元素存入哈希表。
http://www.dtcms.com/a/549530.html

相关文章:

  • Trait 对象与动态分发的权衡:Rust 多态性的代价与收益
  • 基于element-ui二次封装后的组件如何在storybook中展示
  • 零基础新手小白快速了解掌握服务集群与自动化运维(十六)集群部署模块——LVS负载均衡
  • C++面向对象与类和对象之旅(上)----C++重要基础入门知识
  • MR30系列分布式I/O在造型机产线的应用
  • 网站建设优化网站排名河北百度seo点击软件
  • 杭州做网站模板网络搭建基础教程
  • 虚拟机的未来:云计算与边缘计算的核心引擎(一)
  • ​​比亚迪秦新能源汽车动力系统拆装与检测实训MR软件介绍​
  • 仓颉编程(21)扩展
  • 网站建设方案书php做旅游网站
  • 强化网站建设和管理东莞企业建站程序
  • [人工智能-大模型-112]:用通俗易懂的语言,阐述代价函数Cost Function(误差函数、偏差函数、距离函数)
  • 跨平台矩阵如何高效排期?
  • 吴中区网站建设wordpress页面点赞
  • 网站建设需求文案案例html情人节给女朋友做网站
  • MATLAB频散曲线绘制与相速度/群速度分析
  • LeetCode:204. 计数质数
  • MySQL 更新(UPDATE)语句的执行流程,包括 存储引擎内部的文件写入 和 主从复制的同步过程
  • HarmonyOS 系统分享功能概述
  • [crackme]033-dccrackme1
  • PNP机器人将要亮相2025 ROS中国区大会|发表演讲、共探具身智能新未来
  • 寻找大连网站建设企业建站公司是干嘛的
  • Slicer模块系统:核心继承架构解析
  • Mahony姿态解算算法解读
  • Nginx前端配置与服务器部署详解
  • 上海设计网站青岛航拍公司
  • ASR+MT+LLM+TTS 一体化实时翻译字幕系统
  • h5游戏免费下载:视觉差贪吃蛇
  • 【车载开发系列】如何用Parasoft实现跨平台编译环境的配置