1. 两数之和(力扣LeetCode)

news2024/9/22 13:38:04

文章目录

  • 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>();
    }
};

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

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

相关文章

永磁同步电机速度环闭环控制

文章目录 1、速度环分析2、电机参数3、PI计算4、模型仿真4.1 模型总览4.2 实际转速与参考转速对比4.3 转矩波形4.4 相电流采样波形 模型下载地址&#xff1a; 链接: 速度闭环模型&#xff08;速度电流双闭环&#xff09; 1、速度环分析 2、电机参数 Udc24 V Rs0.6 LdLq1.4e-3…

Apache POI 处理excel文件 记录用法

Apache POI 写excel public static void write() throws IOException {//再内存中创建了一个Excel文件XSSFWorkbook excel new XSSFWorkbook();//创建一个sheet页XSSFSheet sheet excel.createSheet("info");//这里创建行对象,这里的rownum 是从0开始的,类似于数…

C++进阶--继承

概念 继承&#xff0c;允许一个类&#xff08;称为子类或派生类&#xff09;从另一个类&#xff08;称为父类或基类&#xff09;继承属性和方法。 继承的主要目的是实现代码的重用和构建类之间的层次关系。通过继承&#xff0c;子类可以获得父类的特性&#xff0c;包括数据成员…

qt-C++笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别

qt-C笔记之QStringList、QList、QString、QChar、QList区别 —— 杭州 2024-01-30 凌晨0:27 参考博文&#xff1a;qt-C笔记之QStringList code review! 文章目录 qt-C笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别1.Qt的字符容器类1.QSt…

维护管理Harbor,docker容器的重启策略

维护管理Harbor 通过HarborWeb创建项目 在 Harbor 仓库中&#xff0c;任何镜像在被 push 到 regsitry 之前都必须有一个自己所属的项目。 单击“项目”&#xff0c;填写项目名称&#xff0c;项目级别若设置为"私有"&#xff0c;则不勾选。如果设置为公共仓库&#…

【个人博客搭建】Hexo安装部署

目录 一、本地构建Hexo (一) 安装前提 1. Node.js 2. Git 3. Hexo (二) 初始化Hexo 1. 初始化博客目录 2. 配置网站基本信息 (三) 主题配置 1. 选择主题 2. 下载主题 (四) 本地启动Hexo 1. 生成静态文件 2. 启动服务 二、部署 (一) 部署到Github Pages 1. 新建…

线性代数------矩阵的运算和逆矩阵

矩阵VS行列式 矩阵是一个数表&#xff0c;而行列式是一个具体的数&#xff1b; 矩阵是使用大写字母表示&#xff0c;行列式是使用类似绝对值的两个竖杠&#xff1b; 矩阵的行数可以不等于列数&#xff0c;但是行列式的行数等于列数&#xff1b; 1.矩阵的数乘就是矩阵的每个…

4D毫米波雷达分类和工程实现

4D毫米波目标检测信息丰富&#xff0c;可获得目标3维位置信息、径向速度vr和rcs等&#xff0c;能够对目标准确分类。 4D毫米波和激光做好时空同步&#xff0c;可以用激光目标给4D毫米波做标注&#xff0c;提升标注效率。 1 激光用做4D毫米波分类真值 128线激光推理的结果作为4…

如何从视频中提取高清图片?可以这样截取

如何从视频中提取高清图片&#xff1f;从视频中提取高清图片可以方便我们制作各种用途所需的素材&#xff0c;如海报、社交媒体配图等。此外&#xff0c;高清图片的细节和色彩也更丰富&#xff0c;可以更好地满足我们的视觉需求。从视频中提取高清图片是一项需要技巧的任务&…

windows上使用anconda安装tensorrt环境

windows上使用anconda安装tensorrt环境 1 安装tensorrt1.1 下载最新的稳定的tensorrt 8.6.1(tensorrt对应的cuda、cudnn等版本是参考链接4)1.2 将tensorrt添加到环境变量1.3 安装tensorrt依赖1.4 安装Pycuda1.5 安装pytorch 2 测试2.1 测试TensorRT 样例(这个测试主要来源于参考…

InsideCli、OutsideCli-电源管理(23国赛真题)

2023全国职业院校技能大赛网络系统管理赛项–模块B&#xff1a;服务部署&#xff08;WindowServer2022&#xff09; 文章目录 题目配置步骤验证 题目 设置电源配置&#xff0c;以便客户端在通电的情况下&#xff0c;永不进入睡眠。 配置步骤 验证

小猪o2o生活通系统更新到了v24.1版本了php文件开源了提供VUE了但是车牌识别功能你真得会用吗

一.车牌识别设置项 车牌识别设置项总开关&#xff1a;系统后台-社区管理-社区配置-车牌识别配置。 平台需要开启车牌识别功能&#xff0c;其次平台可以选择车牌识别功能是由平台配置还是小区自己配置有需要提供代码的可以Q我昵称注明&#xff1a;CSDN网友。如果是平台自己配置&…

2024年火爆《幻兽帕鲁》可以macos系统运行吗?

幻兽帕鲁已经爆了&#xff0c;你和朋友们都是在哪个平台一起玩的&#xff1f; 这款有些类似宝可梦的游戏&#xff0c;已经以野火燎原之势席卷互联网&#xff0c;并且势必会持续一段时间&#xff0c;你可别说你不知道。 《幻兽帕鲁》目前能在哪些平台上运行&#xff1f; 这款由…

linux 下gdal库(python)

之前在windows下安装gdal&#xff0c;先要下安装包再安装。这次在linux上安装&#xff0c;试了一下pip install gdal&#xff0c;不可以。想着linux应该一样&#xff0c;结果一搜网上教程一堆&#xff0c;乱七八糟的。 搞了一个小时 最后发现一句话就可以&#xff01;&#xf…

力扣hot100 分割回文串 集合 dfs

Problem: 131. 分割回文串 文章目录 思路Code&#x1f496; DP预处理版 思路 &#x1f468;‍&#x1f3eb; 参考题解 Code import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List;public class Solution {int n;//字符…

基于二值化图像转GCode的斜向扫描实现

基于二值化图像转GCode的斜向扫描实现 什么是斜向扫描斜向扫描代码示例 基于二值化图像转GCode的斜向扫描实现 什么是斜向扫描 在激光雕刻中&#xff0c;斜向扫描&#xff08;Diagonal Scanning&#xff09;是一种雕刻技术&#xff0c;其中激光头沿着对角线方向来回移动&…

上位机图像处理和嵌入式模块部署(视频处理vs图像处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 从目前发展的情况来看&#xff0c;视频处理会慢慢变成一种主流趋势。这里面的原因很多&#xff0c;比如说现在嵌入式soc的算力越来越强、获取图像的…

【大数据安全】大数据安全的挑战与对策基础设施安全

目录 一、大数据安全的挑战与对策 &#xff08;一&#xff09;数据加密技术 &#xff08;二&#xff09;大数据安全与隐私 &#xff08;三&#xff09;大数据安全保障体系 &#xff08;四&#xff09;华为大数据安全解决方案 二、基础设施安全 &#xff08;一&#xff0…

TSINGSEE青犀视频智慧电梯管理平台,执行精准管理、提升乘梯安全

一、方案背景 随着城市化进程的不断加快&#xff0c;我国已经成为全球最大的电梯生产和消费市场&#xff0c;电梯也成为人们日常生活中不可或缺的一部分。随着电梯数量的激增&#xff0c;电梯老龄化&#xff0c;维保数据不透明&#xff0c;物业管理成本高&#xff0c;政府监管…

用React给XXL-JOB开发一个新皮肤(四):实现用户管理模块

目录 一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语 一. 简述 上一篇文章我们实现登录页面和管理页面的 Layout 骨架&#xff0c;并对接登录和登出接口。这篇…