简介
几周前,我探讨了二和编码挑战的问题,并讨论了解决它的低效和高效方法。今天,我对高效的解决方案进行了改进,提供了一个对JavaScript来说更习惯的解决方案。
二和问题
首先,让我们了解一下二和问题。它通常是以下面的某种形式提出的。
你被要求创建一个需要两个参数的函数。第一个参数,nums ,是一个数组。第二个参数,total ,是一个单一的数字。该函数的输出应该是一个双元素数组,代表nums 中的一对数字,它们的总和为total 。
/**
* @param {number[]} nums
* @param {number} total
* @return {number[]}
*/
const twoSum = (arr, total) => {
// Solution here
};
通常情况下,我们会得到几个有效的输入/输出组合的例子。
input: nums = [1, 2, 3], total = 4
output: [1, 3]
input: nums = [3, 9, 12, 20], total = 21
output: [9, 12]
以前的解决方案
在我之前的博文中,我得出了以下解决方案。它只需要在数组中迭代一次,在迭代过程中向一个对象添加元素。然后,它在该对象中搜索一个 "补充 "值,以配合当前的数组元素。由于对象的哈希表效率,该解决方案的时间复杂度为O(n)。
const twoSum = (nums, total) => {
const previousValues = {};
for (let i = 0; i < nums.length; i++) {
const complement = total - nums[i];
if (previousValues[complement]) {
return [complement, nums[i]];
}
previousValues[nums[i]] = true;
}
};
一个更简明的方法
实际上,JavaScript有一个特定的对象可以帮助解决这个问题:Set 对象。Set 是 "更成文的",因为它是一个存储唯一值(或对象引用)的机制,而不必做我上面做的奇怪的previousValues[nums[i]] = true; 工作。
如果我们改变我们的实现以使用Set ,它可能看起来如下。
const twoSum = (nums, total) => {
const previousValues = new Set();
for (let i = 0; i < nums.length; i++) {
const complement = total - nums[i];
if (previousValues.has(complement)) {
return [complement, nums[i]];
}
previousValues.add(nums[i]);
}
};
根据EcmaScript 2015规范,"集合对象必须使用哈希表或其他机制来实现,这些机制平均提供的访问时间是集合中元素数量的次线性。"因此,我们不一定确定Set 将使用哈希表实现,但我们可以对其效率有信心。
总结
对象缓存和Set 方法都能有效地解决二和问题,但Sets似乎是在JavaScript中处理这个问题的更习惯的方式