不使用 for , while ,递归,如何解决一道简单的算法题?
2017-06-27 20:01
337 查看
今天碰到一道关于的斐波那契数列的题
首先还是要认识一下这个「 斐波那契数列 」,我最早接触都这个数列是在高中的时候。当时在学校,我属于喜欢看课外书的学渣,不知道哪一天就接触到一本 C++ 编程入门书,然后里面就有一节就是如何实现斐波那契数列……还是先看题吧:
例子:
原题链接:https://www.codewars.com/kata/tribonacci-sequence/train/javascript
这种类似的题其实解法挺多的,编程嘛,就要挑战一下新思路,若不使用 for , while 以及 递归的手法,如何实现遍历,并解决这个问题。我使用的手法:
在贴代码之前我先复习一下在 JavaScript 中可以用哪些方法实现数组的遍历
使用 for 或 while
数组提供的遍历的函数
还有就是递归
具体的代码实现感觉写的有点冗长,不过逻辑还是很明了
整个大的函数返回值是一个数组。一个用 Array 创建的新数组使用 apply 把数组的长度确定,然后用 map 进行遍历,遍历的时候对在 map 中对每一项元素进行一些操作:
首先是判断是不是前三项
是前三项直接出来返回对应的值
若不是前三项则开始获取到需要相加的三项元素,我用了 filter 来拿到,之后用 reduce 来进行求和操作(这一步很关键,此时我已经拿到来一项新的值),接着更新传进来的数组,之后返回到 map 中进行下一个操作;直到遍历完整个数组。
在这个题中使用 apply 的一个特殊用法,把一个对象传到 Array 构造函数中,这个对象就包含这这个数组的长度,这个用法并不常见。
方法一属于 es6 的 「 扩展语法 」的用法
这个例子中很清楚得知 Math.max() 里面的参数为数组的时候,并且不做处理,得到不是我们想要的结果
上面的写法不一样,但是做的事情是一样的:通过构造函数 Array 创建了一个数组,其中有些写法很糟糕,比如:方法一,方法二,方法三(没有人会这么创建一个数组,更多是采用字面量的方式)。值的注意的地方是方法二中的写法,创建的其实是这样的数组:
并且有这样的问题,调用 map 或 forEach 的时候不会执行:
所以方法四的优势就显现出来,可以通过 map 或 forEach 进行遍历整个数组
省略 new 的写法参考 《 JavaScript 高级程序设计(第3版) 》第5章-引用类型 5.2-Array 类型(86页)
这也就是我的解答中采用这个方法的原因:能够确定数组的长度,并且内部的元素不确定;但想使用函数的方式进行遍历,恰好有这样的一种方式可以实现。
首先还是要认识一下这个「 斐波那契数列 」,我最早接触都这个数列是在高中的时候。当时在学校,我属于喜欢看课外书的学渣,不知道哪一天就接触到一本 C++ 编程入门书,然后里面就有一节就是如何实现斐波那契数列……还是先看题吧:
题目
给定一个参数数组 arr 和一个要返回的数组的长度 n, 使用一个函数来求出类似斐波那契数列所组成的数组例子:
tribonacci([1, 1, 1] , 5) // [1,1,1,3,5] tribonacci([1, 1, 1], 10) // [1,1,1,3,5,9,17,31,57,105]
原题链接:https://www.codewars.com/kata/tribonacci-sequence/train/javascript
思路
题目的关键:根据例子可以得知,数组中三个相邻的元素的和是数组中新的元素,这个新元素的位置是三个求和元素中的最后一个元素的索引 + 1, 问题来了如何获得数组中对应的相邻的三个元素?这种类似的题其实解法挺多的,编程嘛,就要挑战一下新思路,若不使用 for , while 以及 递归的手法,如何实现遍历,并解决这个问题。我使用的手法:
在贴代码之前我先复习一下在 JavaScript 中可以用哪些方法实现数组的遍历
使用 for 或 while
数组提供的遍历的函数
还有就是递归
解法
个人比较喜欢函数所以这次就使用第二种方法:使用数组中的方法function tribonacci(signature,n){ // 处理遍历的元素,得到一个新的元素 let handleThree = (index) => { // 前数组三项永远都是不改变,是传进来的三项 if (index < signature.length) { return signature[index]; } else { // 过滤出数组中对应的三项元素,求和并更新传进来的数组, let addItem = signature .filter((item, signIndex) => (index - 3) <= signIndex) .reduce((itemB, itemA) => itemB + itemA) signature.push(addItem); return addItem; } } // 得到最后的结果 return Array.apply(null, {length: Number(n)}) .map((item, index) => handleThree(index)); }
具体的代码实现感觉写的有点冗长,不过逻辑还是很明了
整个大的函数返回值是一个数组。一个用 Array 创建的新数组使用 apply 把数组的长度确定,然后用 map 进行遍历,遍历的时候对在 map 中对每一项元素进行一些操作:
首先是判断是不是前三项
是前三项直接出来返回对应的值
若不是前三项则开始获取到需要相加的三项元素,我用了 filter 来拿到,之后用 reduce 来进行求和操作(这一步很关键,此时我已经拿到来一项新的值),接着更新传进来的数组,之后返回到 map 中进行下一个操作;直到遍历完整个数组。
在这个题中使用 apply 的一个特殊用法,把一个对象传到 Array 构造函数中,这个对象就包含这这个数组的长度,这个用法并不常见。
apply
很多人可能知道 apply , call 在扩充函数作用域的情况之下他们的异同之处。其实 apply 还有一个特殊的用处,就是用来传递特殊的值例子一:求数组中最大值
let arr = [1, 2, 3, 4, 5, 6]; Math.max(num); // NaN // 方法一 es6之后的写法 Math.max(...num); // 6 // 方法二 es6之前的写法 Math.max.apply(null, num); // 6
方法一属于 es6 的 「 扩展语法 」的用法
这个例子中很清楚得知 Math.max() 里面的参数为数组的时候,并且不做处理,得到不是我们想要的结果
例子二:使用 apply 填充数组
// 方法一 Array.apply(null, ['5']); // ['5'] // 方法二 Array.apply(null, [5]); // [undefined x 5] // 方法三 得到的结果等价于 方法二 Array(5); // [undefined x 5] // 方法四 Array.apply(null, {length: 5}); // [undefined, undefined, undefined, undefined, undefined]
上面的写法不一样,但是做的事情是一样的:通过构造函数 Array 创建了一个数组,其中有些写法很糟糕,比如:方法一,方法二,方法三(没有人会这么创建一个数组,更多是采用字面量的方式)。值的注意的地方是方法二中的写法,创建的其实是这样的数组:
// 方法二 Array.apply(null, [5]); // [, , , , ,] 或 [, , , , , ,]
并且有这样的问题,调用 map 或 forEach 的时候不会执行:
let arr = Array.apply(null, [5]); arr.forEach((index) => index); //不会执行
所以方法四的优势就显现出来,可以通过 map 或 forEach 进行遍历整个数组
let arr = Array.apply(null, {length: 5}); // [undefined, undefined, undefined, undefined, undefined] arr.map((el, index) => index); //[0, 1, 2, 3, 4]
省略 new 的写法参考 《 JavaScript 高级程序设计(第3版) 》第5章-引用类型 5.2-Array 类型(86页)
这也就是我的解答中采用这个方法的原因:能够确定数组的长度,并且内部的元素不确定;但想使用函数的方式进行遍历,恰好有这样的一种方式可以实现。
欢迎交流新的解题思路
相关文章推荐
- 一道可以使用Trie高级数据结构解决的算法题
- 每天学习一算法系列(12) (求1+2+…+n,不能使用乘除法,for、while、if 、else、switch、case 等关键字以及条件判断语句)
- 每天一道算法题(13)——使用递归颠倒栈
- python学习之输入输出,if,while,for,简单的turtle使用
- 【算法题】题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)
- 如何解决unexpected end of file while looking for precompiled header directive的问题
- 如何解决这个问题:unexpected end of file while looking for precompiled header directive,
- 不使用for,while循环打印99乘法表(使用递归)
- 《github一天一道算法题》:动态规划法解决最长公共子序列(LCS)问题的最简单方法
- 如何解决unexpected end of file while looking for precompiled header directive的问题
- 如何解决unexpected end of file while looking for precompiled header directive的问题
- ZOJ 1312 题解这是一道简单题但容易出错,不需要使用任和算法就可做出来,而且很快。我的AC 0ms
- 一道数列的规律题(使用递归解决)
- 大雾课论文《浅谈简单使用计算机与算法快速解决物理问题》
- 如何使用Debugging Tools for Windows (windebug)简单的使用心得
- 如何在while和for中使用ssh
- 一道面试题:求1+2+…+n,不使用乘除法、for、while、if 、else、switch、case 等关键字
- python中的while和for语句的简单使用
- mysql压缩包如何使用及PoolableConnectionFactory 和Access denied for user 'testdb'@'localhost'问题的解决