有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。

244 阅读4分钟

LeetCode 网站对于程序员而言,是一个极具价值的平台。它不仅提供了海量的编程练习题,涵盖了各种算法和数据结构,帮助程序员不断提升编程技能和解决问题的能力;还是程序员准备面试的重要资源,许多公司的技术面试题都能在这里找到影子。

开始刷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]

方法一(暴力枚举法)

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    var 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]
        }
    }
};

思路分析

我们可以从题目中得知两个数是不同的。

大致思路:

我们需要先在数组下标为i(i初始值为0)的数开始遍历,在遍历过程中让其加上除自己的其他数;我们通过从i+1下标开始遍历选择第二个数,并判断两数之和是否为target的值。

为什么第二次遍历是从i+1开始向后遍历呢?

是因为这样可以防止出现返回两个同样下标的结果,也可以避免进行重复计算。

但是该方法的时间复杂度为O(n^2),并不高效。

案例

nums =[3,2,4]
target =6

过程:

  • 当i=0,j=1时,3+2!=6
  • 当i=0,j=2时,3+4!=6
  • 当i=1,j=2时,2+4=6
  • 输出[1,2]

方法二(通过数组寻找差值)

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

思路分析

我们上个方法的思路是找2个数求和并判断是否为target的值。

我们也可以通过用target减去第一个数的值得出差值,再在数组中寻找该差值数的位置。

我们可以通过JavaScript数组的indexOf()方法。indexOf()方法用于在数组中查找指定元素,并返回其首次出现的位置索引。如果没有找到该元素,则返回 -1。也可以指定开始寻找的位置。

首先,我们在数组下标为i(i初始值为0)的数开始遍历,用a获取target - nums[i]的差值;再用indexOf()方法在下标为i+1开始往后寻找该差值的下标并通过b存取;

根据b是否为-1判断是否存在该插值数;如果存在则返回[a,b],不存在则i+1,再次循环操作,直到找到为止。

但是该代码看上去只有一次for循环,但是时间复杂度还是O(n^2)。因为indexOf()方法也需要进行遍历才能实现。

案例

nums =[3,2,4]
target =6

过程:

  • 当i=0时,a=6-3,b=-1
  • 当i=1时,a=6-2,b=2
  • 输出[1,2]

方法三(通过对象寻找差值)

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

思路分析

上面两个方法的效率并不高,我们要怎么提高效率呢?

第二个方法是通过数组的indexOf()方法遍历数组寻找。我们可以用对象存储差值,然后通过获取对象的值检查数组中是否存在该差值。

为什么这个方法会提高效率呢?

这是因为对象的查找操作可以直接通过键来快速获取对应的值。时间复杂度为O(1)。

如果对象中没有找到差值则会返回undefined。

我们创建一个对象a用来存储差值以及被减数的下标(差值:被减数的下标);我们在数组下标为i(i初始值为0)的数开始遍历,首先判断对象a中是否存在nums[i]元素,如果存在则返回[i,nums[i]元素的值],如果不存在则将target-nums[i]得出的差值当作a的元素,并把i作为该元素的值,然后循环。

案例

nums =[3,2,4]
target =6

过程:

在第一次遍历过程中是不可能有返回值的,因为a对象没有元素。

  • 当i=0时,a[nums[i]]为undefined,a{3:0}
  • 当i=1时,a[nums[i]]为undefined,a{3:0,4:1}
  • 当i=2时,a[nums[i]]不是undefined而是4,可以在a中找到。
  • 输出[2,1]