【发布时间】:2020-02-09 17:31:01
【问题描述】:
给定一个包含重复的整数数组,返回一个所有索引对总和为零的数组。
[1, 2, 3, -1, 5, -5, 7, 9, -7, 2, -2] -> [ [ 3, 0 ], [ 5, 4 ], [ 8, 6 ], [ 10, 1 ], [ 10, 9 ] ]
我的 JS 解决方案:
function pairs(values, i) {
if (values) {
values.push(i);
return values;
}
return [i];
}
function twoSum(arr) {
const results = [];
const map = new Map();
arr.forEach((ele, i) => {
if (map.get(-ele)) {
map.get(-ele).forEach((e) => results.push([i, e]));
}
map.set(ele, pairs(map.get(ele), i));
});
return results;
}
来自 Ruby,这是我的 Ruby 解决方案:
def two_sum(arr)
hash = Hash.new { |h, k| h[k] = [] }
arr.each.with_index.each_with_object([]) do |(ele, i), results|
if hash.key?(-ele)
hash[-ele].each { |e| results << [i, e] }
end
hash[ele] << i
end
end
这个想法是每个 hashmap 键都有一个数组,对于数组中的每个元素,我们检查 hashmap 是否有一个 -element 键,如果有,则将当前索引和每个值的对推送到结果数组.
如何让 JS 解决方案更加地道?我在 JS 默认库中找不到以下内容(与 Ruby 相比):
- 将一个可枚举对象简化为另一个可枚举对象(each_with_object)。
- 初始化一个映射,使每个新键对应一个对象(Hash.new([])、Hash.new(0) 等)。
稍微重构了所选的解决方案,结果如下:
function twoSum(arr) {
const hash = new Map();
return arr.reduce((results, ele, i) => {
if (hash.has(-ele)) hash.get(-ele).forEach((e) => results.push([i, e]));
hash.get(ele) ? hash.get(ele).push(i) : hash.set(ele, [i]);
return results;
}, []);
}
【问题讨论】:
-
我认为更惯用的 Ruby 解决方案是
[*0...arr.size].combination(2).select { |i,j| arr[i] == -arr[j] }。
标签: javascript ruby