js 高级算法 - 动态规划

主要是看了《数据结构与算法》有所感悟,虽然这本书被挺多人诟病的,说这有漏洞那有漏洞,但并不妨碍我们从中学习知识。

其实像在我们前端的开发中,用到的高级算法并不多,大部分情况if语句,for语句,swith语句等等,就可以解决了。稍微复杂的,可能会想到用递归去的解决。

但要注意的是递归写起来简洁,但实际上执行的效率并不高。

我们再看看动态规划的算法:

动态规划解决方案从底部开始解决问题, 将所有小问题解决掉, 然后合并成一个整体解决方案, 从而解决掉整个大问题 。

实例举例  (计算斐波那契数列)

斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........

这个数列从第3项开始,每一项都等于前两项之和。

针对这个数列,可以用一个递归的函数去计算第n项 数值

 // 斐波那契数列
            function recurFib(n) {
                if(n < 2){
                    return n ;
                }else {
//                    document.write("第"+(n-1)+"次计算&nbsp;n-1="+(n-1)+recurFib(n-1)+‘&nbsp;&nbsp;&nbsp;‘);
//                    document.write("n-2="+(n-2)+recurFib(n-2)+"<br>");
                    return recurFib(n-1)+recurFib(n-2)
                }
            }

确实是个非常简洁的代码,上面有被注释的代码 ,是用来打印出当n=多少,要执行多少次函数,不过明眼人一眼就能看出来执行的次数随着n的变大,次数也会非常恐怖增长。

当n=5的时候,递归树已经长的很大了……可以预见当n=10,甚至n=100的时候……

…………………………………………………………………………………………………………………………………………………………………………………………………………………………

明白了递归函数执行效率之差,我们再来看的动态规划是如何做的

  function dynFib(n) {
            let val = [];
            for(let i = 0; i <= n; ++i){
                val[i]=0;
            }
            if(n ===1 || n  === 2){
                return 1;
            }
            else {
                val[1] =1;
                val[2] = 2;
                for(let i = 3; i <= n; ++i){
                    val[i] = val  [i-1] +val[i-2] ;
                }
            }
            return val[n-1]
        }

通过数组 val 中保存了中间结果, 如果要计算的斐波那契数是 1 或者 2, 那么 if 语句会返回 1。 否则,数值 1 和 2 将被保存在 val 数组中 1 和 2 的位置。

循环将会从 3 到输入的参数之间进行遍历, 将数组的每个元素赋值为前两个元素之和, 循环结束, 数组的最后一个元素值即为最终计算得到的斐波那契数值, 这个数值也将作为函数的返回值。

接下来可以写个简单的测试函数,来对比两者的运行时间。

        // 定义一个测试函数,将待测函数作为参数传入
        function test(func,n){
            let start = new Date().getTime();//起始时间
            let res = func(n);//执行待测函数
            document.write(‘<br>‘+‘当n=‘+n+‘的时候&nbsp;‘+res+‘<br>‘);
            let end = new Date().getTime();//结束时间
            return (end - start)+"ms";//返回函数执行需要时间
        }

打印函数执行

     let time = test(recurFib,40);
        document.write(time);
        let time2 = test(dynFib,40);
        document.write(time2);

结果如下:

最后, 你或许已经意识到在使用迭代的方案计算斐波那契数列时, 是可以不使用数组的。

需要用到数组的原因是因为动态规划算法通常需要将中间结果保存起来。

以下是迭代版本的斐波那契函数义 

        function iterFib(n) {
            let last = 1;
            let nextLast = 1;
            let result = 1;
            for (let i = 2; i < n; ++i) {
                result = last + nextLast;
                nextLast = last;
                last = result;
            }
            return result;
        }

当然这个迭代版本的与数组的版本的效率也是相同的。

参考文献   https://book.douban.com/subject/25945449/

时间: 2024-10-08 09:44:53

js 高级算法 - 动态规划的相关文章

高级算法——动态规划(斐波那契函数实例)

//使用递归去解决问题虽然简洁, 但效率不高,转为动态规划较好 function recurFib(n) {//斐波那契数列——递归 if (n <= 2) { return 1; } else { return recurFib(n - 1) + recurFib(n - 2); } } function dynFib(n) {//斐波那契数列——动态规划 var val = []; if (n == 1 || n == 2) { return 1; } else { val[1] = 1;

面试高级算法梳理笔记

面试高级算法梳理笔记 1.1 说明 本篇为<挑战程序设计竞赛(第2版)>读书笔记系列,旨在: 梳理算法逻辑 探索优化思路 深入代码细节 1.2 目录 原文首发于个人博客Jennica.Space,按算法难度划分为初中高三个级别,详细目录及链接如下: 初级篇 穷竭搜索 贪心 动态规划 数据结构 图论 数论 中级篇 二分搜索 常用技巧 数据结构(二) 动态规划(二) 网络流 计算几何 高级篇 数论(二) 博弈论 图论(二) 常用技巧(二) 智慧搜索 分治 字符串 1.3 题解 配套习题及详解同步发

Freecodecamp 高级算法(个人向)

freecodecamp 高级算法地址戳这里. freecodecamp的初级和中级算法,基本给个思路就能完成,而高级算法稍微麻烦了一点,所以我会把自己的解答思路写清楚,如果有错误或者更好的解法,欢迎留言. Validate US Telephone Numbers 如果传入字符串是一个有效的美国电话号码,则返回 true. 简单来说,美国号码的规则就是,国家代码(必须为1),然后就是3,3,4的数字组合,前三个数字可以用括号包起来.另外就是间隔使用空格或者"-". 因为输入值肯定是字

算法——动态规划篇——最长公共子序列

问题描述      最长公共子序列,英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列.       解决最长公共子序列,一种常用的办法,就是穷举法,组合出所有的情况,但是这样对于长序列的情况来说,是非常不实际.. 假设现在有两个序列,x[]={'A','B','C','B','D','A','B'};y[]={'B','D','C','A'

FCC之JS基础算法总结1

1.翻转字符串 解决思路:先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串. 1 function reverseString(str) { 2 var arr = []; 3 arr = str.split(""); 4 arr.reverse(); 5 str = arr.join(""); 6 return str; 7 } 8 9 reverseString("hello"); 主要是对String

&lt;JS高级程序设计3&gt;_PART3

1.ECMAScript中所有数都以IEEE-754 64位格式存储,但位操作符不直接操作64位的值.是先64位转换成32位的整数,再操作,得到结果再转成64位. 2.首位是符号位.之后的31位代表整数的值. 3.用toString(2)打印二进制,得到的是被处理过的二进制. 4.按位非(NOT)~,数转成二进制,取反.相当于把操作数先变负再-1; 5.按位与(AND)&,两个数的二进制,有一个0结果就是0,两个都是1才为1. 6.按位或(OR)|,有一个1结果为1,都是0才为0. 7.按位异或

算法——动态规划篇——斐波那契数列

斐波那契数列,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理.准晶体结构.化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1960年代起出版了<斐波纳契数列>季刊,专门刊载这方面的研究成果. 以上内容来自百度百科.. 今天主要是想用动态规划的思想求解斐波那契数列,用来观察动态规划带来的优势,空间换时间,不重复求解

惰性函数——JS高级

原文地址:http://www.cnblogs.com/galenyip/p/4613430.html 我们先来看一下js的异步提交. XHR我们在原生的时候常常用到,因为常用到,我们更多把封装到了工具库中 先看下他最常用的实现 1 // 旧方法 2 3 function createXHR() { 4 var xhr; 5 try{ 6 xhr = new XMLHttpRequest(); 7 }catch(e) { 8 handleErr(e); 9 10 try { 11 xhr = n

&lt;JS高级程序设计3&gt;_PART4

1.基本数据类型:Undefined,null,Number,String,Boolean.引用数据类型:保存在内存中的对象. 2.JS不允许直接访问内存中的位置,不能直接操作对象的内存空间.所以操作对象时,实际上是操作的对象的引用,而不是实际的对象. 3. var num1 = 1; var num2 = num1; 一个基本类型的变量向另一个赋值时,执行了复制操作,两个变量互不影响. var obj1 = new Object(); var obj2 = obj1; obj1.age = 2