为什么外卖平台能快速匹配你凑满减的商品组合?为什么购物APP能秒算哪两件商品加起来刚好达标优惠?核心就是今天要讲的两数之和算法。这是算法入门的经典题,也是大厂笔试高频考点,看似简单的几行代码,藏着“空间换时间”的核心算法思维。读完这篇,你能掌握两数之和的核心原理、哈希集合的应用逻辑、代码逐行拆解3个核心点,新手也能秒懂。
一、算法核心原理
两数之和算法的核心问题很简单:给定一组数字和一个目标值,判断其中是否存在两个数相加等于这个目标值。
我们可以用一个生活化的比喻理解它:就像你去参加配对游戏,手里拿个小本本(哈希集合),每遇到一个人就把他的名字记下来。游戏规则是找一个和自己相加等于目标数的搭档,所以你每遇到新的人,先翻小本本看看有没有他的“互补人”(目标值减当前数),有就立刻配对成功,没有就把当前人记下来继续找。
如果用笨办法(暴力枚举),要把每两个人都配对试一遍,时间复杂度是O(n²)(大白话:处理100个数字要10000步);而用哈希集合的方法,时间复杂度是O(n)(处理100个数字只要100步),效率提升百倍。不过这个方法需要额外存数字,空间复杂度是O(n),这就是算法里“用空间换时间”的典型思路,即牺牲一点内存,换极致的执行效率。
二、代码逐行解析
先看完整的TypeScript代码(新手也能看懂,核心逻辑和JavaScript完全一致):
/** * 判断数组中是否存在两个数相加等于目标值 * @param nums 数字数组 * @param target 目标和 * @returns 存在返回true,否则返回false */function hasTwoSum(nums: number[], target: number): boolean { // 初始化哈希集合,用于存储已经遍历过的数字 const seen = new Set<number>(); // 先把第一个数字存入集合,作为初始值 seen.add(nums[0]); // 从第二个数字开始遍历(因为第一个已经存过了) for (let i = 1; i < nums.length; i++) { // 计算当前数字的"互补数":目标值 - 当前数 const complement = target - nums[i]; // 检查互补数是否已经在集合中(即是否遍历过) if(seen.has(complement)) { // 找到则直接返回true return true; } // 没找到就把当前数存入集合,继续遍历 seen.add(nums[i]); } // 遍历完都没找到,返回false return false;}
接下来逐模块拆解,搞懂每一行的作用:
1. 初始化哈希集合
const seen = new Set<number>();
2. 存入第一个元素
对应算法逻辑:先把第一个数字记在小本本上,为后续配对做准备。
🔴关键易错点:新手容易漏掉这一步,直接从i=0开始循环,会导致检查 target - nums[0] 时集合为空,或者把当前数和自己配对(比如nums=[3], target=6,错误返回true)。
3. 循环遍历剩余元素
for (let i = 1; i < nums.length; i++) { const complement = target - nums[i]; if(seen.has(complement)) { return true; } seen.add(nums[i]);}
const complement = target - nums[i]:算出当前数字需要的“搭档数”,比如当前数是7,目标值是9,互补数就是2。
if(seen.has(complement)):查小本本里有没有这个搭档数,有就说明之前遍历过的数字里有能和当前数相加等于目标值的,直接返回true。
seen.add(nums[i]):没找到搭档就把当前数记下来,留给后面的数字配对。
4. 遍历结束返回false
三、算法应用场景与拓展
1. 真实应用场景
两数之和的核心是“快速查找互补元素”,这个思路在实际开发中随处可见:
电商凑单计算:用户选满减目标后,APP快速判断购物车中是否有两件商品价格相加达标,实时提示凑单建议;
金融账单核对:财务系统核查回款时,快速判断是否有两笔交易金额相加等于目标回款额,减少人工核对成本;
运动数据匹配:健身APP根据目标消耗卡路里,判断用户当天完成的两段运动时长相加是否刚好达标。
2. 优化方向
需求拓展优化:如果需要返回两个数的索引(而非仅判断是否存在),可把`Set`换成`Map`,Key存数字,Value存对应索引,找到互补数时直接返回`[map.get(complement), i]`;
大数据量优化:处理百万级以上数据时,可分批将数据存入`Set`,每批处理完释放部分内存,避免内存溢出,同时保持O(n)的核心效率。
四、实战小练习
1. 练习题
修改本文的 hasTwoSum 函数,实现:不仅返回是否存在两个数相加等于目标值,还返回这两个数的索引(比如输入nums=[2,7,11,15], target=9,返回[0,1];若不存在则返回[])。
2. 解题思路提示
把存储数据的 Set 换成 Map,因为需要同时记录“数字”和“索引”两个信息;
遍历数组时,先查 Map 中是否有当前数的互补数,若有则返回[Map.get(complement), 当前索引];
若没有则把当前数和索引存入 Map,注意不要让同一个元素和自己配对(比如nums=[3,3], target=6,要返回[0,1]而非[0,0])。
结尾
算法不是背代码,而是理解用更高效的方式解决问题的思路。两数之和的核心是哈希表的快速查找,空间换时间的思想能解决80%的算法效率问题。
你在学习或项目中用过两数之和算法吗?遇到过什么坑?欢迎评论区一起聊聊吧~
关注我,后续拆解更多实用算法,从代码到原理,手把手教你学。