需要在功能中提高性能,找到等于给定总和的最早对

时间:2015-04-07 18:12:58

标签: javascript arrays

我有一个带数组和数字的函数。它会扫描数组,查找数组中最早出现的两个数字,这两个数字相加。我想知道,在性能方面,什么可以帮助这个功能更快地运行。它必须在6秒内处理10,000,000件物品的清单。我现在已经重构了几次,但仍然没有到达那里。

什么是速度最好的数组迭代方法?我认为for循环会是最慢的,所以我选择了map。有更快的方法吗?每隔()?

注意:提供的数组可能有重复,正数或负数(比如说现在最多1000000 ......)。

var low_pair = function (ints, s) {
    var lowNum = ints.length, lowMatch, highNum, clone = [], i;

    for (i = 0; i < ints.length; i++) {
        clone[i] = ints.map(function (n, ind) {
            if (ind !== i && ints[i] + n == s) {
                i > ind ? highNum = i : highNum = ind;
                if (highNum < lowNum) {
                    lowNum = highNum;
                    lowMatch = [ints[i], ints[ind]];
                }
            }
        });
    }
    return lowMatch;
};

4 个答案:

答案 0 :(得分:2)

我们将创建一个函数,它返回最早的元素对,它们总和所需的总和:

function find_pair(l, s) {
    var min_indexes = {};
    for (var i = 0; i < l.length; i++) {
        var a = l[i];
        if ((s - a) in min_indexes)
            return [s - a, a];
        if (!(a in min_indexes))
            min_indexes[a] = i;
    }
}

为此,对于我们处理的每个数字,我们存储其最小索引。如果我们当前处理的是号码a,我们会检查s - a是否设置了最低索引。如果是,这意味着我们找到了我们想要的金额,我们返回两个元素。

例如:

> var l = [2, 3, 4, 5, 5, 7, 8]
> find_pair(l, 10)
[5, 5]
> find_pair(l, 6)
[2, 4]
> find_pair(l, 5)
[2, 3]
> find_pair(l, 15)
[7, 8]
> find_pair([5, 9, 13, -3], 10)
[13, -3]

答案 1 :(得分:1)

  

速度的最佳数组迭代方法是什么?

请参阅What's the fastest way to loop through an array in JavaScript?。但请注意可能会弃用的答案,而且当前的引擎更善于优化不同的东西。您应该始终在自己的目标环境中对自己进行基准测试。

但是,您应该尝试改进算法,而不是寻找原始速度和微观优化。在您的情况下,您可以通过在i处启动内循环来使功能的速度加倍,这样您就不会两次访问所有组合。此外,通过从功能早期返回,您可以加快平均情况(取决于您的数据)。找到最早的一对&#34;你不必遍历整个阵列并计算最小值,你只需要iterate the pairs in the chosen order。如果数据是有序的(或者至少偏向某些分布),你也可以利用它。

我使用

function firstPair(ints, s) {
    var len = ints.length;
    for (var end = 0; end < len; end++)
        for (var i=0, j=end; i<end; i++)
            if (i != --j && ints[i]+ints[j] == s)
                return [i, j];
    for (var start = 0; start < len; start++)
        for (var i=start, j=len; i<len; i++)
            if (i != --j && ints[i]+ints[j] == s)
                return [i, j];
    return null;
}

正如其他答案所示,如果数组中值的范围有限,则可以通过使用查找表 - 交易内存以提高性能来大幅降低算法的复杂性。对已经出现的整数使用位图,它可能如下所示:

function firstPair(ints, s) {
    var map = []; // or, if domain is known and typed arrays are supported, use
//  var map = new Uint16Array(Math.ceil(domainSize / 16));
    for (var i=0; i<ints.length; i++) {
        var x = ints[i],
            r = s - x;
        if (map[r >> 4] & (1 << (r & 0xF))) // get
            return [r, x];
        map[x >> 4] |= 1 << (x & 0xF); // set
    }
    return null;
}

答案 2 :(得分:0)

主要问题是您当前的函数复杂度为O(n ^ 2),这对于10000000元素数组来说太高了。 map函数遍历整个数组。所以你做10000000 * 10000000 = 100万亿&#34;操作&#34;。复杂性需要降低。我最好的猜测 - &gt;在线性循环中使用哈希表。下面是我的示例代码,其中包含1000万个元素的最差情况测试,在我的旧机器上运行大约8秒。它只能运行1000万次而不是100万亿次。

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var low_pair = function (ints, s) {
    var found = {};
    var lowMatch;
    for (var i = 0; i < ints.length; i++) {
        var num = ints[i];
        var prevNum = s-num;
        if (found[prevNum] === true){
            if (prevNum>num){
                lowMatch = [num, prevNum];
            } else {
                lowMatch = [prevNum, num];
            }
            break;
        } else {
            found[num] = true;
        }
    }
    return lowMatch;
};
var test_array_size = 10000000;
var test_array = new Array(test_array_size);
for (var i=0;i<test_array_size;++i){
    test_array[i] = test_array_size-i;
}
console.log("Array initialized");
var start = new Date().getTime();
console.log(low_pair(test_array, 12));
var end = new Date().getTime();
console.log("Running time: "+(end-start)+" ms");
</script>
<head>
<body>
</body>
</html>

答案 3 :(得分:0)

此函数在0ms内始终运行50,000,000个项目数组:

var low_pair = function (s) {
var ints = [];
for(var i = 0; i < 50000000; i++) {
    ints.push(Math.floor(Math.random() * 9));
}
console.time('pair');
var counter = 1;
for (var i = 0; i < ints.length; i++) {
    var sum = ints[i] + ints[counter];
    if (i !== counter) {
        if (sum === s) {
            console.timeEnd('pair');
            return console.log([ints[i], ints[counter]]);
        }
    }
    if (i == counter) {
        counter++;
        i = -1;
    }
}
console.time('pair');
console.log( undefined);
};