【Leetcode 刷题笔记+动画】两数之和

题目描述

给定一个整数数组 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
只会存在一个有效答案

思考

暴力解法是两重循环分别枚举数组中的两个数判断和是否为 target,显然这肯定不是这道题最佳解法。遍历每个数 nums[i] 的同时用哈希表记录 target - nums[i] 和 i,这样下次遍历到数值和 target - nums[i] 相同的数 nums[j] 就可以凑出一个 nums[i] + nums[j] = target,哈希表可以在 O(1)O(1)O(1) 时间内查找 nums[j] 同时返回对应的配对索引 i。这样就可以在一次遍历数组的情形下找出答案。

算法过程

  1. 初始化哈希表:用于存储“目标差值”与“索引”的映射(目标差值 = target - 当前元素值)。
  2. 遍历数组
    • 对每个元素 nums[i],检查哈希表中是否存在该元素(即是否有之前的元素满足“目标差值 = 当前元素值”)。
    • 若存在,直接返回哈希表中记录的索引与当前索引 i
    • 若不存在,将“目标差值(target - nums[i])”和当前索引 i 存入哈希表。
  3. 返回结果:因题目保证有唯一解,遍历过程中必然找到符合条件的两个索引并返回。

该过程通过哈希表将查找时间优化为 O(1)O(1)O(1),整体时间复杂度为 O(n)O(n)O(n),空间复杂度为 O(n)O(n)O(n)

参考代码

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    const map = new Map();

    for (let i = 0; i < nums.length; i++) {
        if (map.has(nums[i])) {
            return [map.get(nums[i]), i];
        }
        map.set(target - nums[i], i);
    }
    
};

算法可视化

在这里插入图片描述

algorithm-visualizer 代码

// import visualization libraries {
const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer');
// }

// 输入参数
const nums =  [3,2,4];
const target = 6;

// define tracer variables {
const arrayTracer = new Array1DTracer('数组');
const mapTracer = new Array1DTracer('哈希表(目标差值→索引)');
const logger = new LogTracer();
Layout.setRoot(new VerticalLayout([arrayTracer, mapTracer, logger]));

arrayTracer.set(nums);
mapTracer.set([]);
Tracer.delay();
// }

function twoSum(nums, target) {
    const map = new Map();
    let mapEntries = []; // 存储哈希表条目用于可视化

    logger.println(`目标值: ${target},寻找和为目标值的两个元素索引`);
    Tracer.delay();

    for (let i = 0; i < nums.length; i++) {
        // 高亮当前处理的数组元素
        arrayTracer.select(i);
        logger.println(`处理索引 ${i},元素值: ${nums[i]}`);
        Tracer.delay();

        // 检查哈希表中是否存在匹配的目标差值
        if (map.has(nums[i])) {
            const matchIndex = map.get(nums[i]);
            // 高亮两个匹配的元素
            arrayTracer.select(matchIndex, i);
            logger.println(`找到匹配!索引 ${matchIndex}(值 ${nums[matchIndex]})和索引 ${i}(值 ${nums[i]})的和为 ${target}`);
            Tracer.delay(1500);
            return [matchIndex, i];
        }

        // 计算目标差值并存入哈希表
        const complement = target - nums[i];
        map.set(complement, i);
        mapEntries.push(`${complement}${i}`); // 用字符串表示键值对
        mapTracer.set(mapEntries); // 更新哈希表可视化
        logger.println(`存入哈希表:目标差值 ${complement} → 索引 ${i}`);
        
        // 取消当前元素高亮(保持窗口移动效果)
        arrayTracer.deselect(i);
        Tracer.delay();
    }
}

// 执行算法
twoSum(nums, target);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值