为递归算法

时间:2016-04-20 19:50:07

标签: javascript recursion memoization

我为partitioning a number编写了一个函数:

var combinations = function (i) {
    var mem = [];
    function inner(n, r, m) {
        for (var k = m; k <= n; k++) {
            if (k == n) {
                r.push(k);
                mem[r] = 1;

                return mem;
            }
            else {
                var copy = r.slice(0);
                copy.push(k);
                inner(n - k, copy, k);
            }
        }
    }

    return inner(i, [], 1);
}

在第二步中我想为这个算法添加一个memoization,但是不能想到以正确的方式实现它,因为直到最后都没有return语句(当返回被指定时,例如在faactorial或fibbinacci中我可以添加memoization)。 有人能把我推向正确的方向吗?

[编辑] 我需要这个算法尽可能快。这是代码战中卡塔的竞争:link 有一项要求必须在6000毫秒内执行,输入最高为330。 这是我能想到的最好的算法,除了如何存储部分结果。

3 个答案:

答案 0 :(得分:0)

我会遵循:

var cache = {};

var combinations = function (i) {
    if ( cache[i] ){
        return cache[i];
    };

    var mem = [];
    function inner(n, r, m) {
        for (var k = m; k <= n; k++) {
            if (k == n) {
                r.push(k);
                mem[r] = 1;

                return mem;
            }
            else {
                var copy = r.slice(0);
                copy.push(k);
                inner(n - k, copy, k);
            }
        }
    }

    cache[i] = inner(i, [], 1);
    return cache[i];
}

但是您必须修改算法才能使用cache(首先计算最大的术语?)

答案 1 :(得分:0)

根据您的其他要求,您可能需要考虑使用its own _.memoize function的underscore.js。

记忆的秘诀在于它利用了闭包的工作方式。在另一个范围内定义函数时,它可以访问该范围内的所有内容。当您将该函数返回到作用域之外的某个位置时,它会引用它在作用域内可以看到的所有内容。

因此要实现记忆,你需要创建一个返回另一个函数的函数,在调用内部函数之前进行记忆检查。

您的代码将如下所示:

/**
 * Because we'll be returning "a function that returns a function" below,
 * this needs to be executed immediately so combinations() is just
 * a standalone function.
 */
var combinations = (function(i) {

    /**
     * mem needs to stay outside the scope of your inner function.
     * If it's in a closure like this, JavaScript will keep its value
     * around as long as combinations still exists.
     */ 
    var mem = [];

    /**
     * A memoization wrapper should return a memoized function
     */
    return function(i) {

        /**
         * Check if mem[i] is set and return it if it has been
         */
        if(mem[i] !== undefined) {
            console.log('returning memoized value');
            return mem[i];    
        }

        function inner(n, r, m) {
            for (var k = m; k <= n; k++) {
                if (k == n) {
                    r.push(k);
                    mem[r] = 1;

                    return mem;
                }
                else {
                    var copy = r.slice(0);
                    copy.push(k);
                    inner(n - k, copy, k);
                }
            }
        }

        /**
         * If the value needs to be computed, we can set it at the same time
         * as we return it instead of putting it in a temporary variable.  
         */ 
        console.log('computed');
        return mem[i] = inner(i, [], 1);
    }

}()); /** <--- That's the rest of the automatic execution */

console.log(combinations(5));
console.log(combinations(5));

答案 2 :(得分:0)

这是一个更简单的代码:

function nr_partitions(n) { return p(n, n); }

function p(sum,largest) {
    if (largest == 0) { return 0; }
    if (sum == 0) { return 1; }
    if (sum < 0) { return 0; }
    return p(sum, largest-1) + p(sum-largest, largest);
}

它使用well-known recurrencep(n,k) = p(n,k-1) + p(n-k, k),其中p(n.k)表示n的分区数,其中最大部分最多为k(例如p (3,2)= 2,因为我们只计算1 + 1 + 1,1 + 2,但不计3)。对于k=n,我们得到n的所有分区的数量。

添加备忘录涉及将字典映射对(sum, largest)存储到p(sum, largest)

相关问题