Leetcode---1.两数之和 (详解加哈希表解释和使用)

文章目录

    • 题目 [两数之和](https://leetcode.cn/problems/two-sum/)
      • 方法一:暴力枚举
      • 代码
      • 方法二:哈希表
      • 代码
    • 哈希表
      • 哈希表的基本概念
        • 哈希函数(Hash Function):
        • 冲突(Collision):
        • 链地址法(Chaining):
        • 开放地址法(Open Addressing):
      • 哈希表的操作
        • 插入(Insert):
        • 查找(Search):
        • 删除(Delete):
      • 哈希表的优点和缺点
        • 优点:
        • 缺点:
      • 基本用法
      • 示例代码
        • 示例 1:计数字符出现次数
        • 示例 2:两数之和问题
      • 注意事项
        • 性能
        • 哈希函数
        • 内存开销

题目 两数之和

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

在这里插入图片描述

方法一:暴力枚举

思路及算法

最容易想到的方法是枚举数组中的每一个数 x,寻找数组中是否存在 target - x。

当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x。

代码

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 {};
    }
};

复杂度分析

时间复杂度:O(N2),其中 N 是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。

空间复杂度:O(1).

方法二:哈希表

思路及算法

注意到方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高。因此,我们需要一种更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出它的索引。

使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N) 降低到 O(1)。

这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;
        for (int i = 0; i < nums.size(); ++i) {
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end()) {
                return {it->second, i};
            }
            hashtable[nums[i]] = i;
        }
        return {};
    }
};

复杂度分析

时间复杂度:O(N),其中 N 是数组中的元素数量。对于每一个元素 x,我们可以 O(1) 地寻找 target - x。

空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。

哈希表

哈希表的基本概念

哈希函数(Hash Function):
  1. 哈希函数将输入的键转换为哈希码,这个哈希码通常是一个整数。
  2. 哈希码用于确定键值对在哈希表中的存储位置。
  3. 一个好的哈希函数应当均匀地分布键,减少冲突的发生。
冲突(Collision):
  1. 当两个不同的键被哈希函数映射到同一个存储位置时,称为冲突。
  2. 处理冲突的方法主要有两种:链地址法(Chaining)和开放地址法(Open Addressing)。
链地址法(Chaining):
  1. 每个存储桶存储一个链表或其他数据结构来处理冲突。
  2. 当冲突发生时,新键值对被插入到对应存储桶的链表中。
开放地址法(Open Addressing):
  1. 当冲突发生时,寻找另一个空的存储桶来存储冲突的键值对。
  2. 常见的开放地址法包括线性探测(Linear Probing)、二次探测(Quadratic Probing)和双重散列(Double Hashing)。

哈希表的操作

插入(Insert):
  1. 计算键的哈希码,找到对应的存储桶。
  2. 如果没有冲突,直接插入。
  3. 如果有冲突,根据冲突解决策略进行处理(例如链地址法或开放地址法)。
查找(Search):
  1. 计算键的哈希码,找到对应的存储桶。
  2. 在存储桶中查找键值对。
  3. 如果使用链地址法,可能需要遍历链表。
删除(Delete):
  1. 计算键的哈希码,找到对应的存储桶。
  2. 在存储桶中查找并删除键值对。
  3. 如果使用链地址法,可能需要遍历链表。

哈希表的优点和缺点

优点:
  1. 快速查找、插入和删除: 平均情况下,这些操作的时间复杂度都是 O(1)。
  2. 实现简单: 相对于平衡树等复杂数据结构,哈希表的实现较为简单。
缺点:
  1. 需要处理冲突: 尽管冲突不可避免,但冲突处理机制(如链地址法或开放地址法)会影响性能。
  2. 内存消耗: 哈希表通常需要额外的内存来存储链表或解决冲突,这在存储空间有限的情况下可能是个问题。
  3. 无法有序遍历: 哈希表中的元素没有特定顺序,因此不能按顺序遍历所有键值对。

基本用法

在C++中,unordered_map 是标准库(STL)中的一种关联容器,提供了键值对的哈希表实现。下面是一些常见的操作:

  1. 引入头文件
#include <unordered_map>
  • 在使用 unordered_map 之前,需要引入 <unordered_map> 头文件。
  1. 声明一个哈希表
std::unordered_map<int, int> hashtable;
  • 声明一个键为 int,值也为 int 的哈希表。
  1. 插入元素
hashtable[1] = 100;
hashtable.insert({2, 200});
  • 使用 [] 操作符或 insert 方法插入键值对。
  1. 访问元素
int value = hashtable[1];
auto it = hashtable.find(2);
if (it != hashtable.end()) {
    std::cout << "Found: " << it->second << std::endl;
}
  • 使用 [] 操作符访问元素或使用 find 方法查找元素。
  1. 删除元素
hashtable.erase(1);
  • 使用 erase 方法删除键值对。
  1. 遍历哈希表
for (const auto& pair : hashtable) {
    std::cout << pair.first << ": " << pair.second << std::endl;
}

使用范围 for 循环遍历哈希表中的所有键值对。

示例代码

下面是一些具体示例,展示如何使用 unordered_map:

示例 1:计数字符出现次数
#include <unordered_map>
#include <iostream>
#include <string>

int main() {
    std::string str = "hello world";
    std::unordered_map<char, int> char_count;

    // 统计每个字符出现的次数
    for (char c : str) {
        if (c != ' ') {
            char_count[c]++;
        }
    }

    // 输出字符出现的次数
    for (const auto& pair : char_count) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}
示例 2:两数之和问题
#include <unordered_map>
#include <vector>
#include <iostream>

std::vector<int> twoSum(const std::vector<int>& nums, int target) {
    std::unordered_map<int, int> hashtable;
    for (int i = 0; i < nums.size(); ++i) {
        int complement = target - nums[i];
        auto it = hashtable.find(complement);
        if (it != hashtable.end()) {
            return {it->second, i};
        }
        hashtable[nums[i]] = i;
    }
    return {};
}

int main() {
    std::vector<int> nums = {2, 7, 11, 15};
    int target = 9;
    std::vector<int> result = twoSum(nums, target);
    if (!result.empty()) {
        std::cout << "Indices: " << result[0] << ", " << result[1] << std::endl;
    } else {
        std::cout << "No solution found." << std::endl;
    }
    return 0;
}

注意事项

性能
  1. unordered_map 提供平均 O(1) 的插入、查找和删除操作,但在最坏情况下,这些操作可能是 O(n) 的。
  2. 哈希表的性能高度依赖于哈希函数的质量和负载因子(元素数量与桶的数量之比)。
哈希函数
  1. 自定义类型作为键时,需要提供自定义的哈希函数和相等函数。
内存开销
  1. unordered_map 在存储键值对时会使用额外的内存来维护哈希桶。

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

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

相关文章

Linux查看进程命令ps和top

Linux 是一种自由和开放源代码的操作系统&#xff0c;它的使用在全球范围内非常广泛。在 Linux 中&#xff0c;进程是操作系统中最重要的组成部分之一&#xff0c;它代表了正在运行的程序。了解如何查看正在运行的进程是非常重要的&#xff0c;因为它可以帮助你了解系统的运行状…

Qwen学习笔记4:Qwen 7B模型调用天气API实现天气的实时查询

前言 在学习Qwen模型的函数调用功能后&#xff0c;进一步尝试利用本地的Qwen模型访问OpenWeather API来获取实时的天气情况。 参考代码来源于视频教程&#xff1a; 简单粗暴&#xff0c;轻松配置Qwen模型查询实时数据功能_哔哩哔哩_bilibili 说明 该代码运行前&#xff0c…

基于51单片机的AD/DA转换的串口通信proteus仿真(附源码)

文章目录 一、前言二、PCF85911.介绍2.原理图3.引脚介绍 三、仿真图1.未仿真时2.仿真时 四、仿真程序main.cIIC.c 五、总结 一、前言 AT89C52是一款经典的8051系列单片机&#xff0c;它通常不包含内置的模数转换器&#xff08;ADC&#xff09;或数字模拟转换器&#xff08;DAC…

「Python绘图」绘制奥运五环

python 绘制奥运五环 一、预期结果 二、核心代码 import turtle print("开始绘制奥运五环")# 创建Turtle对象 pen turtle.Turtle() pen.shape("turtle") pen.pensize(8)print("绘制蓝色圆") pen.up() pen.goto(50-170,0) pen.down() pen.color…

进程信号 signal

文章目录 信号基础信号的产生OS中的时间 信号的保存sigset_tsigprocmasksigpending 信号的捕捉用户态和内核态sigactionvolatile SIGCHLD 信号基础 生活中的信号 你在网上买了很多件商品&#xff0c;再等待不同商品快递的到来。但即便快递没有到来&#xff0c;你也知道快递来临…

HNU-算法设计与分析-作业5

第五次作业【回溯算法】 文章目录 第五次作业【回溯算法】<1> 算法分析题5-3 回溯法重写0-1背包<2> 算法分析题5-5 旅行商问题&#xff08;剪枝&#xff09;<3> 算法实现题5-2 最小长度电路板排列问题<4> 算法实现题5-7 n色方柱问题<5> 算法实现…

[论文阅读]FINE-TUNE THE PRETRAINED ATST MODEL FOR SOUND EVENT DETECTION

摘要 本研究提出了一种微调预训练模型ATST&#xff08;音频师生转换模型&#xff09;的方法&#xff0c;用于声音事件检测&#xff08;SED&#xff09;。通过引入ATST-Frame模型&#xff0c;该方法在DCASE挑战任务4数据集上取得了新的SOTA结果&#xff0c;有效解决了预训练模型…

Leetcode - 130双周赛

目录 一&#xff0c;3142. 判断矩阵是否满足条件 二&#xff0c;3143. 正方形中的最多点数 三&#xff0c;3144. 分割字符频率相等的最少子字符串 四&#xff0c;3145. 大数组元素的乘积 一&#xff0c;3142. 判断矩阵是否满足条件 本题题意&#xff0c;满足每一列的数全部…

LLama3大模型本地部署 仅需6步完成对话模型本地安装部署。附送可视化ui安装、自定义模型目录,修改模型保存地址,第三方微调模型、中文模型下载地址

本篇分为三部分 一&#xff1a;6步完成llama3大模型本地部署 二&#xff1a;8步完成llama3可视化对话界面安装 三&#xff1a;重设模型文件路径 四&#xff1a;微调模型、中文模型下载资源分享 一、LLama3 大模型本地部署安装 首先去mata官网下载ollama客户端 Ollama 选择合适…

Linux操作系统最著名的两大系列Red Hat和Debian

Linux操作系统可以根据其背后的项目或社区分为不同的系列&#xff0c;其中最著名的两大系列是Red Hat系列和Debian系列。 1.著名的两大系列是Red Hat和Debian Red Hat系列&#xff1a; Red Hat Enterprise Linux (RHEL)&#xff1a;这是Red Hat公司推出的企业级操作系统&#…

计算机网络-路由策略与路由控制一

到目前为止我们学习了路由与交换基础&#xff0c;路由协议有静态、RIP、OSPF、IS-IS等&#xff0c;但是根据实际组网需求&#xff0c;往往需要实施一些路由策略对路由信息进行过滤、属性设置等操作&#xff0c;通过对路由的控制&#xff0c;可以影响数据流量转发。 因此我们开始…

Vitis HLS 学习笔记--资源绑定-使用URAM(1)

目录 1. 简介 2. 代码分析 2.1 存储器代码 2.2 Implementation报告 2.3 存储器类型指定 2.4 存储器初始化 3. 总结 1. 简介 在博文《Vitis HLS 学习笔记--资源绑定-使用URAM-CSDN博客》中&#xff0c;介绍了如何在Vitis HLS环境下设计一个简易的存储器模型。 通过以下…

Skywalking配置traceId

1.引言 1.1 SkyWalking概述 SkyWalking是一个开源的分布式系统观测平台&#xff0c;旨在解决微服务和云原生架构中常见的性能监控和故障排除问题。自2015年由Apache基金会孵化以来&#xff0c;SkyWalking已经成为全球范围内广泛使用的APM&#xff08;应用性能管理&#xff09…

Selenium 自动化 —— 高级交互(click、sendKeys、submit、clear、select)

更多关于Selenium的知识请访问CSND论坛“兰亭序咖啡”的专栏&#xff1a;专栏《Selenium 从入门到精通》 ​​ 1. 前言 这是我的《Selenium从入门到精通》专栏的第11篇文章&#xff0c;前面花了很多时间在元素的定位上。不管是爬虫和自动化&#xff0c;找到元素后&#xff0c…

jvisualvm安装Visual GC插件

给jdk自带的jvisualvm安装Visual GC插件&#xff0c;遇到We’re sorry the java.net site has closed&#xff08;我们很抱歉java.net网站已经关闭&#xff09; 1、找到新的更新地址 visualvm新访问地址&#xff1a;https://visualvm.github.io/index.html 进入“Plugins”&am…

【介绍下Python多线程,什么是Python多线程】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

一个可自动生成行排号的excel VBA小工具

如下图&#xff0c;点击“生成行排号”按钮即可生成想要的行排号 基本用法如下&#xff1a; 1、设置顺序排列的行排号&#xff08;每排的行号一致&#xff0c;行的方向排序方向也一致&#xff09; 2、设置顺序排列的行排号&#xff08;行号从小到大排列&#xff0c;而不受排的…

UEC++学习(十五)创建、查找、加入会话

创建会话 基于上篇配置steam在线子系统之后&#xff0c;在Character.h中声明一个会话创建完成时的委托以及回调函数。 #include "Interfaces/OnlineSessionInterface.h"public://指向在线会话界面的指针,将会话接口存储在里面TSharedPtr<class IOnlineSession, ES…

电脑缺失api-ms-win-crt-runtime-l1-1-0.dll文件的几种修复方法

当您在使用电脑过程中遇到程序启动失败&#xff0c;提示缺少“api-ms-win-crt-runtime-l1-1-0.dll”文件时&#xff0c;不必过于焦虑&#xff0c;此问题通常与Windows系统的Visual C Redistributable组件未正确安装或损坏有关。小编将介绍5种修复电脑缺失api-ms-win-crt-runtim…

STM32-09-IWDG

文章目录 STM32 IWDG1. IWDG2. IWDG框图3. IWDG寄存器4. IWDG寄存器操作步骤5. IWDG溢出时间计算6. IWDG配置步骤7. 代码实现 STM32 IWDG 1. IWDG IWDG Independent watchdog&#xff0c;即独立看门狗&#xff0c;本质上是一个定时器&#xff0c;这个定时器有一个输出端&#…