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

[优选算法专题一双指针——两数之和](双指针和哈希表)

题目链接

LeetCode两数之和

题目描述

题目解析

注意:前提条件:输入的数组numbers是已排序的。

核心思路:双指针法

利用数组已排序的特性,通过两个指针从两端向中间移动,快速定位符合条件的两个数,时间复杂度为O(n)(n 为数组长度),空间复杂度为O(1),比哈希表解法更优。

具体步骤:

  1. 初始化指针

    • left指针指向数组起始位置(下标 0)。
    • right指针指向数组末尾位置(下标numbers.size()-1)。
  2. 循环查找目标和

    • 计算两指针指向元素的和sum = numbers[left] + numbers[right]
    • sum > target:说明右侧元素过大,将right指针左移(right--),减小总和。
    • sum < target:说明左侧元素过小,将left指针右移(left++),增大总和。
    • sum == target:找到符合条件的两个元素,返回它们的下标(注意 + 1,因为题目要求从 1 开始计数)。
  3. 边界处理

    • 若循环结束仍未找到(理论上题目保证有解,此步可省略),返回{-1, -1}

示例说明:

假设输入:numbers = [2, 7, 11, 15]target = 9

  • 初始left=0(值 2),right=3(值 15),sum=17 > 9 → right--(指向 11)。
  • sum=2+11=13 > 9 → right--(指向 7)。
  • sum=2+7=9 == target → 返回{0+1, 1+1} = {1, 2}

完整代码

复杂度分析

1. 时间复杂度:O (n)

  • 分析:算法使用双指针(left 和 right)从数组两端向中间移动,每次循环仅移动一个指针,直到两指针相遇(left >= right)。
  • 最坏情况:两个指针总共移动的次数不会超过数组长度 n(例如,目标值需要最小元素和最大元素相加时,指针从两端移动到相遇,总步数为 n 级)。
  • 结论:时间复杂度为 O(n),其中 n 是数组 numbers 的长度。

2. 空间复杂度:O (1)

  • 分析:算法仅使用了常数个额外变量(leftrightsum),没有使用与输入规模相关的额外空间(如哈希表、数组等)。
  • 结论:空间复杂度为 O(1),属于原地(in-place)算法。

如果是无序的,这里我们可以使用哈希表来解决!

哈希表法(无序)

解法思路:哈希表(空间换时间)

这个解法的核心是利用 哈希表(unordered_map) 存储已经遍历过的元素及其下标,通过一次遍历就能找到答案,避免了暴力解法的二次循环。

具体逻辑:

  1. 遍历数组中的每个元素 nums[j]j 是当前下标)
  2. 计算与当前元素互补的数值:complement = target - nums[j]
  3. 检查哈希表中是否存在 complement

  • 若存在,说明之前已经遍历过值为 complement 的元素(下标为 i),则 i 和 j 就是答案
  • 若不存在,将当前元素 nums[j] 和其下标 j 存入哈希表,继续遍历

代码执行流程(分步演示)

  • 我们以 nums = [5, 4, 3, 2, 8] 且 target = 12 为例,详细演示代码的执行过程。

    预期结果

    在这个例子中,数组中 4 + 8 = 12,对应的下标是 1 和 4,因此最终应该返回 [1, 4]

    代码执行步骤拆解

    我们按照代码的执行顺序,一步步分析哈希表的变化和每轮循环的操作:

    • 初始化

      • 创建空哈希表 idx = {}(用于存储已遍历元素的值和下标)
      • 循环变量 j 从 0 开始
    • 第一轮循环(j=0,当前元素 nums [0]=5)

      • 计算互补值:complement = target - nums[j] = 12 - 5 = 7
      • 检查哈希表 idx 中是否存在 7:此时哈希表为空,未找到
      • 将当前元素存入哈希表:idx[5] = 0(现在哈希表为 {5:0}
      • 继续下一轮循环
    • 第二轮循环(j=1,当前元素 nums [1]=4)

      • 计算互补值:complement = 12 - 4 = 8
      • 检查哈希表 idx 中是否存在 8:当前哈希表只有 5,未找到
      • 将当前元素存入哈希表:idx[4] = 1(现在哈希表为 {5:0, 4:1}
      • 继续下一轮循环
    • 第三轮循环(j=2,当前元素 nums [2]=3)

      • 计算互补值:complement = 12 - 3 = 9
      • 检查哈希表 idx 中是否存在 9:哈希表中只有 5 和 4,未找到
      • 将当前元素存入哈希表:idx[3] = 2(现在哈希表为 {5:0, 4:1, 3:2}
      • 继续下一轮循环
    • 第四轮循环(j=3,当前元素 nums [3]=2)

      • 计算互补值:complement = 12 - 2 = 10
      • 检查哈希表 idx 中是否存在 10:哈希表中没有 10,未找到
      • 将当前元素存入哈希表:idx[2] = 3(现在哈希表为 {5:0, 4:1, 3:2, 2:3}
      • 继续下一轮循环
    • 第五轮循环(j=4,当前元素 nums [4]=8)

      • 计算互补值:complement = 12 - 8 = 4
      • 检查哈希表 idx 中是否存在 4:此时哈希表中存在 4,对应的下标是 1(即 idx[4] = 1
      • 找到答案,直接返回 [1, 4](互补元素的下标 1 和当前元素的下标 4
      • 程序结束

代码细节解析

完整代码

  • 哈希表的作用

    • unordered_map<int, int> idx 中,key 是数组元素的值,value 是该元素的下标
    • 哈希表的查找操作是 O(1) 时间复杂度,比数组查找(O (n))快得多
  • 循环设计

    • 原代码中的 for (int j = 0; ; j++) 其实隐含了 j < nums.size() 的条件(题目保证有解,所以一定会在循环内返回)
    • 标准写法应该是 for (int j = 0; j < nums.size(); j++),更严谨
  • 避免重复使用元素

    • 因为我们是先检查哈希表,再将当前元素存入哈希表,所以哈希表中永远只包含「当前元素之前的元素」
    • 这就保证了不会出现「自己和自己相加」的情况(例如 nums = [3,3] 时,第一个 3 存入哈希表后,第二个 3 才会查找并命中)
  • 返回值

    • 题目保证有且仅有一个解,所以循环内一定会找到答案并返回
    • 理论上不需要最后的 return {},但为了满足 C++ 语法(函数必须有返回值),通常会加上

时间复杂度为 O(n)

http://www.xdnf.cn/news/17199.html

相关文章:

  • Qwen-Image开源模型实战
  • Spring、Spring MVC、MyBatis 和 Spring Boot的关系
  • 防火墙环境下的全网服务器数据自动化备份平台搭建:基于 rsync 的完整实施指南
  • 板块三章节3——NFS 服务器
  • 秋招笔记-8.7
  • Redis面试精讲 Day 13:Redis Cluster集群设计与原理
  • 解决 Nginx 反代中 proxy_ssl_name 环境变量失效问题:网页能打开但登录失败
  • Vue3获取当前页面相对路径
  • SMT工具实践:Moses工具的配置和小语种平行语料训练统计翻译模型完整实现
  • 六类注定烂尾的甲方软件外包必看!这类甲方不要理-优雅草卓伊凡
  • 【Docker】Redis基础命令在Docker中的使用
  • 试用一个用v语言编写的单文件数据库vsql
  • 计算机视觉--opencv(代码详细教程)
  • 投资股票心态
  • Swift 实战:高效设计 Tic-Tac-Toe 游戏逻辑(LeetCode 348)
  • 微算法科技(NASDAQ:MLGO)利用集成学习方法,实现更低成本、更稳健的区块链虚拟货币交易价格预测
  • 软件运行时 ffmpeg.dll 丢失怎么办?从原因排查到完美修复的完整方案
  • 开源大模型实战:GPT-OSS本地部署与全面测评
  • [失败记录] 使用HBuilderX创建的uniapp vue3项目添加tailwindcss3的完整过程
  • 前端三大核心要素以及前后端通讯
  • VBA之Word应用第四章第一节:段落集合Paragraphs对象(一)
  • 告别复杂配置!cpolar让Prometheus监控突破网络限制
  • 在新建word中使用以前文件中的列表样式
  • 使用nvm管理多个node版本(附安装教程)
  • Mac+Chrome滚动截图
  • windows内核研究(内存管理-线性地址的管理)
  • 前端百分比展示导致后端 BigDecimal 转换异常的排查与解决
  • 【数据库】如何从本地电脑连接服务器上的MySQL数据库?
  • 第二集 测试概念
  • 3a服务器的基本功能1之身份认证