算法篇--两数之和,梦开始的地方

目录

    • 1.概念:
    • 2.两数之和
      • (1).暴力破解法
      • (2).使用哈希表
    • 3.区别

1.概念:

非形式地说,算法(algorithm)就是任何良定义的计算过程,该过程取某个值或值的集合作为输入并产生某个值或值的集合作为输出。这样算法就是把输人转换成输出的计算步骤的一个序列。


我们也可以把算法看成是用于求解良说明的计算问题的工具。一般来说,问题陈述说明了期望的输入/输出关系。算法则描述一个特定的计算过程来实现该输入/输出关系。


例如,我们可能需要把一个数列排成非递减序。实际上,这个问题经常出现,并且为引人许多标准的设计技术和分析工具提供了足够的理由。下面是我们关于排序问题的形式定义。


输入;n个数的一个序列


输出:输人序列的一个排列,满足a1<=a2…<=an.例如,给定输入序列《31,41,59,26,41,58),排序算法将返回序列<26,31,41,41,58.59)作为输出。这样的输人序列称为排序问题的一个实例(instance)。一般来说,问题实例由计算该问题解所必需的(满足问题陈述中强加的各种约束的)输入组成。


因为许多程序使用排序作为一个中间步,所以排序是计算机科学中的一个基本操作。因此已有许多好的排序算法供我们任意使用。对于给定应用,哪个算法最好依赖于以下因素:将被排序的项数、这些项已被稍微排序的程度、关于项值的可能限制、计算机的体系结构,以及将使用的存储设备的种类(主存、磁盘或者磁带)


2.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

例如:

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

(1).暴力破解法

针对这种问题我们可以使用双层for循环进行暴力破解,示例代码如下:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    for (var i= 0; i < nums.length; i++){
        for (var j = i+1 ; j < nums.length ; j++){
            if (nums[i] + nums[j] === target){
                return [i,j]
            }
        }
    }
    return {}
};

针对这段代码我们进行大概的分析,这段代码的时间复杂度为 O(n^2), 其中 n 是数组 nums 的长度。这是因为代码使用了两个嵌套的循环来遍历数组。第一个循环的时间复杂度为 O(n),第二个循环的时间复杂度取决于当前索引 i,平均为 O(n/2)。因此,总体的时间复杂度为 O(n * n/2),即 O(n^2)。

代码的空间复杂度为 O(1),因为它只使用了常量级的额外空间来存储变量 i、j,并没有使用额外的数据结构或数组。无论输入的规模如何增长,代码所需的额外空间量是固定的。


(2).使用哈希表

/**
 * @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++) {
        const complement = target - nums[i];
        if (map.has(complement)) {
            return [map.get(complement), i]; // 找到两数之和等于目标值的索引
        }
        map.set(nums[i], i); // 将元素及其索引添加到哈希表
    }
    return []; // 若不存在两数之和等于目标值,返回空数组
};

这段代码使用了哈希表来降低时间复杂度,使得时间复杂度为 O(n),其中 n 是数组 nums 的长度。具体解析如下:

代码首先创建了一个空的哈希表 map,用于存储数组元素及其索引。

在遍历数组 nums 的过程中,对于每个元素 nums[i],通过计算 target - nums[i] 得到与之配对的补数 complement。

然后,检查哈希表 map 中是否存在 complement,如果存在,说明在当前索引 i 之前已经出现过补数 complement,即找到了满足条件的两个数,可以直接返回两个索引的数组

如果不存在 complement,则将当前元素 nums[i] 及其索引 i 添加到哈希表 map 中。

最终,如果没有找到满足条件的两个数,返回一个空数组。

由于只需要遍历一次数组,且哈希表的查找操作的时间复杂度为 O(1),因此总体时间复杂度为 O(n)

空间复杂度方面,额外使用了一个哈希表 map,其所需空间取决于输入数组的大小,因此空间复杂度为 O(n)。


3.区别

第一段代码使用了双重循环来遍历数组,查找满足条件的两个数。虽然代码简单,但时间复杂度为 O(n^2),在面对大规模数据时效率较低。此代码适用于数据量较小的情况。

第二段代码使用了哈希表来优化查找过程,将时间复杂度降至 O(n)。这在处理大规模数据时表现更优。它以空间复杂度为代价,利用哈希表存储元素及其索引,以更快地查找到满足条件的两个数。

因此,如果输入规模较小时,第一段代码可能更简单且适用。而在处理大规模数据时,第二段代码更有效率。

你可能感兴趣的:(算法,算法,数据结构,javascript,两数之和)