1. 两数之和(力扣LeetCode)

文章目录

  • 1. 两数之和
    • 题目描述
    • 哈希表:map
    • 二分查找
    • 暴力:双重for循环

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) 的算法吗?

哈希表:map

使用map需要明确两点:

  • map用来做什么
  • map中key和value分别表示什么

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

接下来是map中key和value分别表示什么。

这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。

所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

过程如下:
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 创建一个哈希表来存储数组元素和它们的索引
        unordered_map<int, int> map;//map.find() 返回的是一个迭代器(std::unordered_map<int, int>::iterator),它存储的元素是 std::pair<const Key, T> 类型的对象

        // 遍历数组中的每个元素,索引为i
        for (int i = 0; i < nums.size(); i++) {//枚举a:这里其实是将a+b=target转换为target-a=b,然后在数组中查找b是否存在
            // 尝试在哈希表中找到与当前元素相加等于target的元素
            auto b = map.find(target - nums[i]);

            // 如果找到了这样的元素
            if (b != map.end()) {
                // 返回一个包含两个索引的数组,i是当前元素的索引,
                // b->second是之前存储在哈希表中的配对元素的索引
                return { i, b->second };
            }

            // 如果没有找到配对元素,将当前元素的值和索引存入哈希表
            map.insert(pair<int, int>(nums[i], i));//相当于map[nums[i]]=i;
        }

        // 如果没有找到任何满足条件的元素对,返回一个空数组
        return {};
    }
};

  • auto:auto 关键字用于自动类型推断。它指示编译器自动推断变量的类型,根据变量的初始化表达式来确定其类型。

  • map.find():

    • 如果键 target - nums[i] 存在于 map 中,find 函数返回一个迭代器,指向 unordered_map 中含有该键的键值对。
    • 如果键不存在,find 函数返回一个特殊的迭代器 map.end(),这个迭代器指向 unordered_map 结尾的位置,这表明搜索失败。
  • pair:在C++中,pair 是一个结构,定义在 头文件中,它可以将两个值合并成一个单元。这两个值可以是不同的数据类型。pair 最常见的用途是在关联容器中,如 std::map 或 std::unordered_map,其中每个元素都是一个键值对。

    • pair 的构造函数接受两个参数,分别对应 pair 的两个成员:first 和 second,其中:

      • first 成员变量将存储键(nums[i]),
      • second 成员变量将存储与键关联的值(i)。

二分查找

这道题并不推荐二分,因为需要考虑的东西太多:

  • 使用二分算法查找需要对数组排序,一旦排序就会破坏原来的下标,我这里用一个新的num2复制 nums 数组,因为后面会对 nums 进行排序,这样做是为了保留原始元素的索引。
  • 因为下标的变动还需要使用num2去寻找原来的下标
  • 寻找原来下标中也有坑,如果两个数相同,就需要从下一个数开始寻找,不然会得到相同的下标:如下
// 如果两个找到的数字相同,需要找到第二个相同数字的索引
                if (nums[i] == nums[z]) v = v + 1;
                else v = 0;

总代码如下,比较复杂,所以并不推荐二分,因为一开始感觉像我做过的A-B 数对这道题,觉得可以用二分查找做出来,仅此记录而已

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 复制原数组nums到num2,用于在排序后找回原始索引
        vector<int> num2(nums.begin(), nums.end());
        
        // 对nums进行快速排序
        quick_sort(nums, 0, nums.size() - 1);
        vector<int> num;

        // 遍历排序后的数组,寻找是否存在两个数的和等于target
        for (int i = 0; i < nums.size(); i++) {
            // 计算与当前数字nums[i]相配对的数字
            int b = target - nums[i];
            
            // 使用二分查找法在nums中查找b
            int z = find(b, nums);
            cout << z << endl;

            // 如果找到了b,并且它的索引不是i(确保不是同一个元素)
            if (z != -1 && z != i) {
                // 查找nums[i]在原数组num2中的索引
                int v = find_xb(0, num2, nums[i]);
                num.push_back(v);
                
                // 如果两个找到的数字相同,需要找到第二个相同数字的索引
                if (nums[i] == nums[z]) v = v + 1;
                else v = 0;

                // 查找nums[z]在原数组num2中的索引
                num.push_back(find_xb(v, num2, nums[z]));
                // 返回结果数组,包含两个找到的索引
                return num;
            }
            // 如果没有找到,则继续循环
            else continue;
        }
        // 如果没有找到任何匹配的元素对,返回一个空数组
        return vector<int>();
    }

// 快速排序算法的实现
private:
    void quick_sort(vector<int>& nums, int l, int r) {
        // 如果子数组长度为0或1,则返回
        if (l >= r) return;

        // 初始化指针和基准值
        int i = l - 1, j = r + 1, x = nums[(l + r) >> 1];
        while (i < j) {
            // 移动左指针直到找到一个大于等于x的元素
            do i++; while (nums[i] < x);
            // 移动右指针直到找到一个小于等于x的元素
            do j--; while (nums[j] > x);
            // 如果i<j,交换两个元素
            if (i < j) swap(nums[i], nums[j]);
        }

        // 递归地对左右子数组继续排序
        quick_sort(nums, l, j);
        quick_sort(nums, j + 1, r);
    }

// 二分查找算法的实现
    int find(int n, vector<int>& nums) {
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (nums[mid] >= n) r = mid;
            else l = mid + 1;
        }
        // 检查是否找到目标n
        if (nums[l] == n) return l;
        return -1;
    }

// 在原数组中查找给定的数字并返回其索引
    int find_xb(int v, vector<int>& num, int n) {
        // 从给定的起始索引v开始查找
        for (int i = v; i < num.size(); i++) {
            // 如果找到了,就返回索引
            if (num[i] == n)
                return i;
        }
        // 这个循环理论上不会运行到结尾,因为前面的逻辑保证了n在num中
        // 这里没有返回值,实际上应该有一个返回值来保证函数完整性
        return -1; // 增加默认返回值
    }
};

暴力:双重for循环

该代码的工作原理是:

  • 遍历数组 nums 中的每个元素,索引为 i。
  • 对于每个 i,再次遍历其之后的每个元素,索引为 j。
  • 对于每对 (i, j),检查 nums[i] 和 nums[j] 的和是否等于 target。
  • 如果找到这样的一对 (i, j),则将它们的索引作为答案返回。
  • 如果遍历完所有的元素对也没有找到满足条件的对,那么返回一个空的数组。

时间复杂度和空间复杂度分析:

  • 时间复杂度:O(n^2),因为有两个嵌套循环,每个循环都可能遍历整个数组 nums。
  • 空间复杂度:O(1),因为除了存储结果所需的空间之外,不需要额外的存储空间。
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 定义一个向量来存放结果
        vector<int> num;

        // 外层循环遍历数组中的每一个元素,除了最后一个
        for (int i = 0; i < nums.size() - 1; i++) {
            // 内层循环从当前元素的下一个开始遍历
            for (int j = i + 1; j < nums.size(); j++) {
                // 检查当前对的元素和是否等于目标值
                if (nums[i] + nums[j] == target) {
                    // 如果等于目标值,则将两个数字的索引添加到结果向量中
                    num.push_back(i);
                    num.push_back(j);
                    // 返回结果,不需要继续查找
                    return num;
                }
            }
        }
        // 如果没有找到符合条件的两个数,返回空向量
        return vector<int>();
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EDTER:融合transformer的边缘检测网络

原文链接&#xff1a;EDTER 首先回顾viT部分&#xff1a; 和ViT一样&#xff0c;先把图像分割为P*P大小的patch&#xff0c;分别经过映射得到tokens&#xff1a;patch embeddings。后面也加了ViT一样的position embedding&#xff0c;得到combined embeddings。 ViT中的Tran…

一篇文章让你搞懂性能测试6大类型及其关系!

性能测试是软件测试过程的一个关键环节&#xff0c;用于确定和验证应用程序或系统在各种操作条件下的性能特征。 目标是确保软件在高负载、高压力、长时间运行以及其他非标准情况下仍能保持预期的行为和效率。 一. 性能测试的主要类型 1. 基线测试&#xff08;Baseline Test…

​学者观察 | 区块链技术理论研究与实践观察——中央财经大学朱建明

导语 当下区块链研究成果质量越来越高&#xff0c;技术应用越来越成熟。在现阶段的研究中存在哪些短板需要弥补&#xff0c;如何将研究成果转化为推动数字经济高质量发展的实际应用&#xff0c;区块链技术与其他新技术结合发展将带来哪些新的机遇&#xff1f; 中央财经大学朱…

阿里云推出 3.x Java 探针,解锁应用观测与治理的全新姿势

作者&#xff1a;张铭辉、泮圣伟 前言 随着春节大促即将到来&#xff0c;为了确保线上业务高效稳定地运行&#xff0c;电商企业大多会对旗下关键业务应用进行多轮测试。通过模拟线上较高流量的请求&#xff0c;来观察服务性能的实际表现。以某企业的业务测试报告举例&#xf…

呼吸灯--FPGA

目录 1.breath_led.v 2.tb_breath_led.v 呼吸灯就是从完全熄灭到完全点亮&#xff0c;再从完全点亮到完全熄灭。具体就是通过控制PWM的占空比控制亮灭程度。 绘制PWM波的步骤就是&#xff0c;首先灯是在第一个时钟周期保持高电平熄灭状态&#xff0c;在第二个时钟周期保持1/1…

Logstash 7.7.1版本安装系统梳理

前言 上一篇文章介绍了 《ElasticSearch7.7.1集群搭建 & Kibana安装》&#xff0c;今天说一下 Logstash的安卓和配置&#xff1b; Logstash是一个开源的数据收集引擎&#xff0c;具有实时管道功能。它可以动态地将来自不同数据源的数据统一起来&#xff0c;并将数据标准化…

Redis集群环境搭建

Redis集群环境搭建 Redis主从复制 概念 主从复制是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器&#xff0c;前者称为主节点(master/leader)&#xff0c;后者称为从节点(slave/followe)&#xff1b;数据的复制是单向的&#xff0c;只能从主节点到从节点&a…

使用Promethues+Grafana监控Elasticsearch

PromethuesGrafana监控Elasticsearch 监控选用说明指标上报流程说明实现监控的步骤搭建elasticsearch-exporter服务搭建promethues和grafana服务 监控选用说明 虽然用Kibana来监控ES&#xff0c;能展示一些关键指标&#xff0c;但ES本身收集的指标并不全面&#xff0c;还需要在…

【刷题】牛客网 NC132 环形链表的约瑟夫问题

NC132 环形链表的约瑟夫问题 题目描述思路一&#xff08;链表直通版&#xff09;思路二&#xff08;数组巧解版&#xff09;思路三&#xff08;变态秒杀版&#xff09;Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff…

【C语言】探索数据结构:单链表和双链表

目录 &#x1f4a1;链表的概念和结构 &#x1f4a1;链表的分类 &#x1f4a1;无头单向非循环链表&#xff08;单链表&#xff09;的实现 定义节点结构 单链表的尾部插入 单链表的头部插入 单链表的尾部删除 单链表的头部删除 在指定位置插入前数据 在指定位置之后插入数…

TypeScript 学习笔记(Day3)

「写在前面」 本文为 b 站黑马程序员 TypeScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. TypeScript 学习笔记&#xff08;Day1&#xff09; 2. TypeScript 学习笔…

科技云报道:新趋势下,国产数据库或“春山可望”

科技云报道原创。 从540亿元到1286亿元——这是中国通信标准化协会大数据技术标准推进委员会针对中国数据库行业给出的一份预测报告。 报告指出&#xff0c;未来五年&#xff0c;中国数据库行业将从百亿级市场跨越成为千亿级市场。 最近两年&#xff0c;中国的数据库行业似乎…

用tar压缩一个文件夹下的所有文件,包括文件夹本身

当你使用tar命令压缩一个文件夹时&#xff0c;默认情况下会包含该文件夹本身及其下所有的文件和子目录。因此&#xff0c;之前的命令同样适用于包括文件夹本身在内的所有内容&#xff1a; tar -czvf archive_name.tar.gz directory_to_compress/ c 表示创建一个新的归档文件。…

使用Eclipse搞Android项目报错

相信现在都没什么人还会用Eclipse来开发的了。 不过安装完后&#xff0c;打开Eclipse会提示我的Jdk版本不符合 --------------------------- Incompatible JVM --------------------------- Version 1.8.0_391 of the JVM is not suitable for this product. Version: 17 or g…

【三维重建】运动恢复结构(SfM)

运动恢复结构是通过三维场景的多张图像&#xff0c;恢复出该场景的三维结构信息以及每张图片对应的摄像机参数。 欧式结构恢复(内参已知&#xff0c;外参未知) 欧式结构恢复问题&#xff1a; 已知&#xff1a;1、n个三维点在m张图像中的对应点的像素坐标 2、相机内参 求解&…

mysql入门到精通003-基础篇-SQL

1、目录 2、SQL通用语法及分类 2.1 SQL通用语法 2.2 SQL分类 3、SQL DDL数据库操作 3.1 SQL DDL表操作-创建&查询 3.1.1 表操作-查询 3.1.2 表操作-创建 create table tb_user(id int comment 编号,name varchar(50) comment 用户名,age int comment 用户名,gender varch…

mysql .ibd 文件过大清理方法

问题 有一个 info_track 表用来临时存储告警推送数据&#xff0c;逻辑处理完成后&#xff0c;会执行 Delete 语句删除对应的记录。 问题&#xff1a;项目现场运行了几个月后&#xff0c;发现磁盘空间莫名占用了过多的存储&#xff0c;> 100GB&#xff0c;且无法释放。 生…

Halcon 拟合

文章目录 算子更多xld算子更多区域算子 Blob 分析案例预处理图像增强降噪图像降噪 图像增强Halcon 基于圆的拟合 Halcon 共线联合案例Halcon 拟合动画案例Halcon 拟合椭圆 算子 二值化算子 &#xff08;二值化后获取的都是区域&#xff09; 二值化算子 clip_region_rel 剪切区域…

【总线接口】3.常见总线、接口GPIO、I2C、SPI、I2S、Modbus

初接触硬件&#xff0c;五花八门的总线、接口一定会让你有些疑惑&#xff0c;我尝试用一系列文章来解开你的疑惑。 系列文章 【总线接口】1.以Xilinx开发板为例&#xff0c;直观的认识硬件接口 【总线接口】2.学习硬件这些年接触过的硬件接口、总线 大汇总 【总线接口】3.常见…

单片机开发通用功能组件

mcu_reuse_development_module 单片机可复用、可通用开发组件&#xff0c;是以中间件思想开发的一套功能模块&#xff0c;将具有代表性或使用次数较多的功能和协议栈封装为独立的组件供开发者使用&#xff0c;开发者仅需通过组件提供的接口对接驱动层和应用层即可使用组件功能…