freeCodeCamp算法题——Basic Algorithm Scripting初级算法题(保姆级解析,让你彻底搞懂基础算法!更新中...)

博主最近也在学习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]]);

这么一看,真的是太优雅了吧! 

思考:这里只有两级的数组,如果有三级呢?四级呢?深嵌套的数组如果找出每个子数组中的最大值呢?递归的话,边界在哪儿呢?

来个一键三连吧!点赞、回复、关注越多!更新的越快!!!

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值