携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 23 天,点击查看活动详情
数对和
原题地址
设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。
示例 1:
输入: nums = [5,6,5], target = 11
输出: [[5,6]]
示例 2:
输入: nums = [5,6,5,6], target = 11
输出: [[5,6],[5,6]]
提示:
nums.length <= 100000
思路分析
方法一
- 首先遍历数组,来统计每个数字出现的次数,方便后续一个数只能属于一个数对;
- 然后在双层遍历数组,若
nums[i] + nums[j] === target时,将这组数对放入res中,然后给map中的nums[i]和nums[j]对应的数据分别减一,保证条件成立; - 在运行过程中,发现若有奇数个可以组成
target的数值时,会出现多一个的情况,查代码发现是因为两个数值相同时,在做减法的时候会出现减掉的次数少一次的情况,因此将相同和不相同的分别来处理; - 最后结果因为遍历次数太多,导致超出时间限制。
方法二
- 吸取方法一的教训后,我们可以缩减遍历次数,争取在一次循环中搞定;
- 循环的过程中,查看是否有满足条件的
target - num1,有的话将对应的次数减少,并且将对应的数对存入res中,若不存在,则将对应的nums[i]的次数统计到map中; - 最后返回
res即可。大大缩减了执行时间。
AC 代码
方法一
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var pairSums = function(nums, target) {
const res = []
const map = {}
for(let i = 0; i < nums.length; i++) {
if(map[nums[i]]) {
map[nums[i]] += 1
} else {
map[nums[i]] = 1
}
}
for(let i = 0; i < nums.length; i++) {
for(let j = 0; j < nums.length, j!== i; j++) {
if(nums[i] + nums[j] === target) {
if(nums[i] !== nums[j] && map[nums[i]] > 0 && map[nums[j]] > 0 || (map[nums[i]] > 1 && nums[i] === nums[j])) {
res.push([nums[i], nums[j]])
map[nums[i]] -= 1
map[nums[j]] -= 1
}
}
}
}
return res
};
结果:
- 执行结果: 超出时间限制
方法二
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var pairSums = function(nums, target) {
const res = []
const map = {}
for(let i = 0; i < nums.length; i++) {
const num1 = nums[i]
const num2 = target - num1;
if (map[num2] && map[num2] > 0) {
map[num2] = map[num2] - 1
res.push([num2, num1])
} else {
const num = map[num1] ? map[num1] + 1 : 1
map[num1] = num
}
}
return res
};
结果:
- 执行结果: 通过
- 执行用时:168 ms, 在所有 JavaScript 提交中击败了80.00%的用户
- 内存消耗:65.4 MB, 在所有 JavaScript 提交中击败了25.71%的用户
- 通过测试用例:42 / 42