晴明的博客园 GitHub      CodePen      CodeWars     

[js] 记忆(memoization) 斐波那契数列(Fibonacci sequence)

#

            var result = [];

            function fn(n) { //典型的斐波那契数列
                if (n == 1) {
                    return 1;
                } else if (n == 2) {
                    return 1;
                } else {
                    if (result[n]) {
                        //缓存
                        return result[n];
                    } else {
                        result[n] = arguments.callee(n - 1) + arguments.callee(n - 2);
                        return result[n];
                    }
                }
            }

 

 

#

            var fibonacci1 = function(n) {
                return n < 2 ? n : fibonacci1(n - 1) + fibonacci1(n - 2);
            };
            //            var fibonacci = function(n) {
            //                return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
            //            };
            for (var i = 0; i <= 10; i += 1) {
                console.log('// ' + i + ': ' + fibonacci1(i));
            }
            //本身被调用了453次
            // 0: 0
            // 1: 1
            // 2: 1
            // 3: 2
            // 4: 3
            // 5: 5
            // 6: 8
            // 7: 13
            // 8: 21
            // 9: 34
            // 10: 55

#

        //fibonacci 调用优化
            //只调用29次
            var fibonacci2 = (function() {
                var memo = [0, 1];
                var fib = function(n) {
                    var result = memo[n];
                    if (typeof result !== 'number') {
                        result = fib(n - 1) + fib(n - 2);
                        memo[n] = result;
                    }
                    return result;
                };
                return fib;
            }());
            for (var i = 0; i <= 10; i += 1) {
                console.log('// ' + i + ': ' + fibonacci2(i));
            }

#

            var mFib = function() {
                var cache = [1, 1]; // 裴波拉契数的前两个数为1, 1
                return function(m) {
                    var len = cache.length,
                        i = len;
                    // 如果m大于cache的长度, 则说明m对应的裴波拉契数不存在, 需要计算
                    if (m > len) {
                        // 当i等于m的时候, 小于i之前的裴波拉契数已经计算过了, 可以直接使用
                        // 有的例子用的for循环, 但while循环更快
                        while (i <= m) {
                            // 裴波拉契数的特点, 后一个数等于前两个数之和
                            // 把计算结果缓存起来, 避免再次计算
                            cache[i] = cache[i - 2] + cache[i - 1];
                            i++;
                        }
                    }
                    // 当裴波拉契数存在时, 直接使用
                    return cache[m - 1];
                }
            }();

#

            //进而产生通用的优化方案 
            var memoizer = function(memo, formula) {
                var recur = function(n) {
                    var result = memo[n];
                    if (typeof result !== 'number') {
                        result = formula(recur, n);
                        memo[n] = result;
                    }
                    return result;
                };
                return recur;
            };
            var fibonacci = memoizer([0, 1], function(recur, n) {
                return recur(n - 1) + recur(n - 2);
            });
            for (var i = 0; i <= 10; i += 1) {
                console.warn('// ' + i + ': ' + fibonacci(i));
            }
            var factorial = memoizer([1, 1], function(recur, n) {
                return n * recur(n - 1);
            });
            for (var i = 0; i <= 10; i += 1) {
                console.warn('// ' + i + ': ' + factorial(i));
            }

 

posted @ 2016-04-02 15:40  晴明桑  阅读(903)  评论(0)    收藏  举报