博主最近也在学习freeCodeCamp的算法题(为什么不去乐扣?因为对前端不友好....可能刷完freeCodeCamp会去刷乐扣吧。另外,星星姐的声音太好听了,这才入了坑)。
声明:很多题目当然不止有一种解法,如果我知道进阶的解法(更“优雅”的代码,不一定代表更快),我会给出思路并列举出来,如果大家有更多更好的解法,欢迎大家在评论区回复,帮助我们这些小白们提高。
另外,题目我会用英文,方便大家查找,我也会给出题目的大概意思,方便大家理解。
1. Convert Celsius to FahrenheitPassed
初始代码:
function convertToF(celsius) {
let fahrenheit;
return fahrenheit;
}
convertToF(30);
翻译:摄氏度℃转成华氏度℉,已经给出了参数celsius代表了摄氏度,要求返回华氏度fahrenheit,之间的关系是℉ = ℃ * 9/5 +32
思路:这道题还是很简单的运算,只需要修改相应的乘法和加法就可以。
答案:
function convertToF(celsius) {
let fahrenheit = celsius * 9/5 + 32;
return fahrenheit;
}
convertToF(30);
进阶:如果类似这样简单的运算,其实不需要另外声明个变量的,可以直接return你的运算
function convertToF(celsius) {
return celsius * 9/5 + 32;
}
convertToF(30);
2. Reverse a String
翻译:翻转一个给定的字符串,并且输出必须也是个字符串,例如reverseString("hello"),应该输出"olleh"。给出了提示:应该先把字符串转换成数组然后再翻转。
思路:1. 字符串转换成数组首先应该想到的就是split方法,这个是字符串内置的方法,可以直接调用,可以传入一个参数,例如空格——split(“ ”),也可以不传参数——默认会将字符串直接分解为数组。
2. 调用split("")方法分解为数组后,可以调用reverse()方法来翻转数组中的内容
3. 数组转字符串的方法有很多(toString,toLocaleString,join),join方法与其他两个方法区别是可以自定义插入的分隔符,另外,如果不传入分隔符,默认是拼接字符串(但是双引号还是要写的join(“”)!!)
所以思路很明确了,使用split(“”)将字符串转化为数组,然后使用reverse()方法翻转数组内容,然后用join("")方法拼接数组内容
答案:
function reverseString(str) {
return str.split("").reverse().join("");
}
reverseString("hello");
进阶:字符串的原型暴露了一个@@iterator方法,有了这个方法我们才得以迭代字符串中的每个字符(例如使用for...of方法迭代字符串)。拥有了这个迭代器之后,字符串就可以使用ES6新增的解构操作符来解构了,这样可以很方便的把字符串分割为字符数组。(红宝书第4版P124)
function reverseString(str) {
return [...str].reverse().join("");
}
reverseString("hello");
3. Factorialize a Number
翻译:返回给定数字的阶乘结果,例如给定的num是5,则5!= 1 * 2 * 3 * 4 * 5 = 120。给定的num是一个大于等于0的数字。
思路:看到阶乘首先应该想到的就是递归,递归就是用来处理重复的操作的,通常的形式就是一个函数通过名称调用自己。
需要注意的是,递归一定要有个条件界限,否则将无限制的递归下去。这里的界限就是num <= 1,当num <= 1时,阶乘结果永远等于1(0的阶乘是1啊!忘了吗?!回去请教下你们高中老师!)
答案:
function factorialize(num) {
if(num <= 1) {
return 1
}else {
return num * factorialize(num - 1);
}
}
factorialize(5);
进阶:虽然这样写是可以的,但是如果把这个函数赋值给其他变量,就会出现问题:(红宝书第4版P306)
这里把factorial()函数保存在了另一个变量anotherFactorial中,然后将 factorial 设置为 null, 于是只保留了一个对原始函数的引用。而在调用 anotherFactorial() 时,要递归调用 factorial() ,但此时 factorial() 已经不是一个函数了,所以会报错。
使用arguments.callee可以避免这个问题。arguments.callee 就是一个指向正在执行的函数的指针,因此可以函数内部递归调用。
function factorialize(num) {
if(num <= 1) {
return 1
}else {
return num * arguments.callee(num - 1);
}
}
但是有个问题就是,在严格模式下是不能访问arguments.callee的,freeCodeCamp也会报错且不会通过。
此时,可以使用命名函数表达式,例如:
const factorialize = (function f(num) {
if(num <= 1) {
return 1
}else {
return num * f(num - 1);
}
});
这里创建了一个命名函数f() ,然后把它赋值给变量factorial。这样表达式名称 f 也不会变化,递归不会再有问题。(但是说这么多,你们下次估计也不会这样用【狗头】)
4. Find the Longest Word in a String
翻译:找出给定的句子中最长的单词,并返回单词的长度。例如:"The quick brown fox jumped over the lazy dog",最长的单词是“jumped”,所以应该返回 6 。
思路:我们可以观察到句子中的每个单词是根据中间的空格来分隔的,我们可以使用split方法先分隔字符串为数组。之后使用循环我们可以获得每个arr[i]的长度。之后就是比较一堆数字的大小,然后返回这个数字就可以了。
但是这些数字是分散的,我们可以选择先把各个长度全部放进一个数组中,然后只需要找出数组中最大的值就可以了。
这里我使用了Math.max的方法,并且使用了ES6的spread方法()即(...arr)。
答案:
function findLongestWordLength(str) {
let arr = str.split(" ");//分离各个单词
let arrLen = [];// 创建个空数组用来存放各个单词的长度
for(let i = 0; i < arr.length; ++i){ //通过循环将单词长度加进去
arrLen.push(arr[i].length);
}
return Math.max(...arrLen)
}
findLongestWordLength("The quick brown fox jumped over the lazy dog");
这里有人可能想到,可以先使用sort排序,然后再直接返回最后一项数字就可以了呀。
天真呐~
sort() 方法会在每一项上调用String() 转型函数,会将数字转化为字符串来比较,所以明明 5 < 10,但是字符串 "10" < "5",除非你给sort方法传入一个比较函数(但是为了这么简单的一道题再封装个比较大小的函数,你觉得值得吗?)
所以直接使用Math.max方法比较好。
进阶:使用数组的map方法代替for循环来获取每个单词的长度
map方法需要传入一个函数,返回一个新数组,新数组的内容就是函数处理后的结果。
例如:
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
这样我们就可以返回一个包含所有单词的长度的新数组。(这里我使用了箭头函数,这个知识点不懂得就去MDN查查吧)
function findLongestWordLength(str) {
let arrLen = str.split(" ").map(val => val.length);// 创建个空数组用来存放各个单词的长度
return Math.max(...arrLen)
}
findLongestWordLength("The quick brown fox jumped over the lazy dog");
5. Return Largest Numbers in Arrays
翻译:返回一个数组,包含给定的嵌套数组中,每一项中最大的值,例如:[ [13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1] ],返回的是[27, 5, 39, 1001]。题目中也说明可以使用简单的 for 循环来获得每一个arr[i]。
思路:经过前面几道题,大家应该知道如何比较数组中的数字了,这里我们先使用for循环来获得里面的每一项 arr[i]。然后使用Math.max和spread方法来找出arr[i]中最大的值。当然,我们需要先创建个空数组来存储各个子数组中的最大值。
答案:
function largestOfFour(arr) {
let newArr = [];
for(let i = 0; i < arr.length; ++i) {
newArr.push(Math.max(...arr[i]))
}
return newArr
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
进阶:我们真的需要for循环吗?处理数组中的每一项并且返回新的数组,你想到了什么?
是的,就是我们上一题学会的 map() 方法啊!
所以我们可以map和Math.max方法结合使用。
function largestOfFour(arr) {
return arr.map( val => Math.max(...val))
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
这么一看,真的是太优雅了吧!
思考:这里只有两级的数组,如果有三级呢?四级呢?深嵌套的数组如果找出每个子数组中的最大值呢?递归的话,边界在哪儿呢?
来个一键三连吧!点赞、回复、关注越多!更新的越快!!!