题目

给定一个整数数组 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
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

Solution

解法—,哈希表

首先进行初步实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function twoSum(nums, target) {
// 用哈希表来存储每个数字的下标
const numToIdx = new Map();
for (let i = 0; i < nums.length; i++) {
// 将每个数字的下标存储到哈希表中
numToIdx.set(nums[i], i);
}

// 枚举数组中的每个数字,并计算它与另一个数字的和
for (let i = 0; i < nums.length; i++) {
// 计算它与另一个数字的和
const num = target - nums[i];

// 如果哈希表中存在该数字,并且它的下标不同于当前的下标,那么我们找到了答案
if (numToIdx.has(num) && numToIdx.get(num) !== i) {
return [i, numToIdx.get(num)];
}
}

// 如果没有找到答案,返回空数组
return [];
}

如果数组中有相同的数字呢,我们可以在哈希表中使用数组来解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function twoSum(nums, target) {
// 用哈希表来存储每个数字的下标
const numToIdx = new Map();
for (let i = 0; i < nums.length; i++) {
// 如果哈希表中已经存在该数字,那么将它的下标添加到数组中
if (numToIdx.has(nums[i])) {
numToIdx.get(nums[i]).push(i);
} else {
// 否则,将该数字的下标存储到哈希表中
numToIdx.set(nums[i], [i]);
}
}

// 枚举数组中的每个数字,并计算它与另一个数字的和
for (let i = 0; i < nums.length; i++) {
// 计算它与另一个数字的和
const num = target - nums[i];

// 如果哈希表中存在该数字
if (numToIdx.has(num)) {
// 遍历数组,找到所有可能的答案
for (const j of numToIdx.get(num)) {
// 如果下标不同,那么找到了答案
if (j !== i) {
return [i, j];
}
}
}
}

// 如果没有找到答案,返回空数组
return [];
}

此种解法的时间复杂度为O(n), 空间复杂度 O(n)

排序 + 双指针

首先,将数组从小到大排序。接下来,定义两个指针,一个指向数组的开头,另一个指向数组的结尾。然后,如果两个指针指向的数字的和大于目标值,就将右指针左移;如果和小于目标值,就将左指针右移。持续这样操作,直到找到答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function twoSum(nums, target) {
// 将数组从小到大排序
nums.sort((a, b) => a - b);

// 定义两个指针,一个指向数组的开头,另一个指向数组的结尾
let left = 0;
let right = nums.length - 1;

// 持续这样操作,直到找到答案
while (left < right) {
// 计算两个指针指向的数字的和
const sum = nums[left] + nums[right];

// 如果和大于目标值,就将右指针左移
if (sum > target) {
right--;
} else if (sum < target) {
// 如果和小于目标值,就将左指针右移
left++;
} else {
// 否则,找到了答案
return [left, right];
}
}

用双指针的方法,时间复杂度为 O(nlogn)。因为我们需要先对数组进行排序,这一步的时间复杂度是 O(nlogn),而排序之后,我们只需要遍历数组一次,所以时间复杂度是 O(n)。因此,总的时间复杂度是 O(nlogn)。

空间复杂度为 O(1),因为我们只需要两个指针来指向数组中的元素,所以不需要额外的空间。

Start Now

哇,
这个蛮有意思,
总能发现很多好玩的事情。
那就记下来!
过了一些天后总是会惊奇的发现, 这真的是我写的嘛, 咋看不懂了呢。

那就这些文字会自己解释自己~

0%