「前端算法面试实战」 第一篇:两数之和问题详解

204 阅读4分钟

从今天开始,我将开启「前端算法面试实战」系列,帮助大家攻克前端面试中的算法难题。作为第一篇文章,我选择了一道面试中的"常客"——两数之和问题,这道题易于理解但解法多样,非常适合作为我们的开篇之作。

问题描述

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

输入:nums = [2, 7, 11, 15], target = 9
输出:[0, 1]
解释:因为 nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1]

解题思路

这道题有多种解法,我们从最基础的方法开始,逐步优化至最优解。

方法一:暴力解法

最直观的解法是使用两层循环,枚举所有可能的数字对,判断它们的和是否等于目标值。

function twoSum(nums, target) {
    const n = nums.length;
    
    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {
            if (nums[i] + nums[j] === target) {
                return [i, j];
            }
        }
    }
    
    return []; // 没有找到符合条件的结果
}
  • 时间复杂度: O(n2)O(n2),其中 nn 是数组的长度
  • 空间复杂度: O(1)O(1),只使用了常数级别的额外空间

方法二:哈希表(一次遍历)

暴力法效率较低,我们可以通过哈希表记录已经遍历过的元素,实现 O(n)O(n) 的时间复杂度。

function twoSum(nums, target) {
    const map = new Map();
    
    for (let i = 0; i < nums.length; i++) {
        const complement = target - nums[i];
        
        if (map.has(complement)) {
            return [map.get(complement), i];
        }
        
        map.set(nums[i], i);
    }
    
    return []; // 没有找到符合条件的结果
}
  • 时间复杂度: O(n)O(n),只需要一次遍历
  • 空间复杂度: O(n)O(n),哈希表最多需要存储 nn 个元素

方法三:排序 + 双指针

如果允许修改原数组,我们还可以使用排序 + 双指针的方法:

function twoSum(nums, target) {
    // 创建一个数组,存储原始索引
    const indices = nums.map((num, index) => ({
        value: num,
        index: index
    }));
    
    // 按照值排序
    indices.sort((a, b) => a.value - b.value);
    
    let left = 0;
    let right = nums.length - 1;
    
    while (left < right) {
        const sum = indices[left].value + indices[right].value;
        
        if (sum === target) {
            return [indices[left].index, indices[right].index];
        } else if (sum < target) {
            left++;
        } else {
            right--;
        }
    }
    
    return [];
}
  • 时间复杂度: O(nlog⁡n)O(nlogn),主要来自排序操作
  • 空间复杂度: O(n)O(n),需要存储原始索引

方法比较与分析

方法时间复杂度空间复杂度优点缺点
暴力解法O(n2)O(n2)O(1)O(1)简单直观,无需额外空间效率低
哈希表O(n)O(n)O(n)O(n)效率高,一次遍历需要额外空间
排序+双指针O(nlog⁡n)O(nlogn)O(n)O(n)理解简单需要排序,效率次之

对于这道题,哈希表法是最优解,它完美地平衡了时间和空间复杂度。面试中,建议直接使用哈希表法,因为它简洁高效。

进阶思考

  1. 如果数组已经排序,你会如何解决?

    • 使用双指针法,时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)
  2. 如果需要找出所有和为 target 的不重复数对呢?

    • 可以先排序,然后使用双指针法,同时处理重复元素
  3. 扩展到三数之和、四数之和问题时,思路如何变化?

    • 三数之和:可以固定一个数,然后在剩余数组中找两数之和
    • 四数之和:可以固定两个数,然后在剩余数组中找两数之和

总结

两数之和是算法面试中的经典问题,也是哈希表应用的典型案例。通过这个问题,我们可以学习到:

  1. 如何从暴力解法优化到高效解法
  2. 如何利用哈希表将查找效率从 O(n)O(n) 提升到 O(1)O(1)
  3. 如何平衡时间复杂度和空间复杂度

在下一篇文章中,我们将探讨另一个前端面试常见算法题:链表的反转。敬请期待!