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]