freeCodeCamp (JavaScript中级算法题)学习

1、范围内的数字求和

我们会传入一个由两个数字组成的数组。 给出一个含有两个数字的数组,我们需要写一个函数,让它返回这两个数字间所有数字(包含这两个数字)的总和。 最低的数字并不总是第一位。

例如,sumAll([4,1]) 应返回 10,因为从 1 到 4(包含 1、4)的所有数字的和是 10

function sumAll(arr) {
  let sum = 0;
  let min = Math.min(arr[0],arr[1]);
  let max = Math.max(arr[0],arr[1]);
  for(let i = min;i<= max; i++){
    sum += i;
  }
  return sum;
}

sumAll([1, 4]);

2、数组的对称差

比较两个数组并返回一个新数组,包含所有只在其中一个数组中出现的元素,排除两个数组都存在的元素。 换言之,我们需要返回两个数组的对称差。

注意:返回数组中的元素顺序不会影响挑战的测试结果。

function diffArray(arr1, arr2) {
  var newArr = [];
  return arr1
  .concat(arr2)
  .filter(item => !arr1.includes(item)||!arr2.includes(item));
}

diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);

3、过滤数组元素

你将获得一个初始数组(destroyer 函数中的第一个参数),后跟一个或多个参数。 从初始数组中移除所有与后续参数相等的元素。

注意: 你可以使用 arguments 对象。

function destroyer(arr) {
//把 destroyer 函数的参数变为数组
var newArr = arguments;
//从初始数组中删除与这些参数具有相同值的所有元素。
    return arr.filter(function(num){
    	//(第一个参数)初始数组内的元素 num 与初始数组后面的多个参数比较,所以 i 从 1 开始。i = 0 时 newArr[0] 就是初始数组
        for(var i=1;i<newArr.length;i++){
            if(num===newArr[i]){
            	//返回 false 返回值数组中不添加 num 元素
                return false;
            }
        }
        //返回 true 返回值数组中添加 unm 元素
        return true;
    });
}

destroyer([1, 2, 3, 1, 2, 3], 2, 3);

4、找出包含特定键值对的对象

创建一个查看对象数组(第一个参数)的函数,并返回具有匹配的名称和值对的所有对象的数组(第二个参数)。 如果要包含在返回的数组中,则源对象的每个名称和值对都必须存在于集合中的对象中。

比如,如果第一个参数是 [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }],第二个参数是 { last: "Capulet" }

function whatIsInAName(collection, source) {
    var arr = [];
  // 只修改这一行下面的代码
  var keys = Object.keys(source);
  arr = collection.filter(function(obj){
    return keys.every(function(key){
      return obj.hasOwnProperty(key)&& obj[key] === source[key];
    });
  });

  // 只修改这一行上面的代码
  return arr;
}

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });

5、短线连接格式

将字符串转换为短线连接格式。 短线连接格式是小写单词全部小写并以破折号分隔。

function spinalCase(str) {
  return str.split(/\s|-|_|(?=[A-Z])/).join("-").toLowerCase();
}

spinalCase('This Is Spinal Tap');

6.儿童黑话

儿童黑话也叫 Pig Latin,是一种英语语言游戏。 规则如下:

- 如果单词以辅音开头,就把第一个辅音字母或第一组辅音簇移到单词的结尾,并在后面加上 ay

- 如果单词以元音开头,只需要在结尾加上 way

function translatePigLatin(str) {
  if(isYuan(str.substr(0,1))){
    str += "way";
  }else{
    let i = 1;
    while(!isYuan(str.substr(i,1))){
      i++;
    }
    str = str.substr(i) + str.substr(0,i) + 'ay';
  }
  return str;
}

function isYuan(str){
  return str === "a"||str === "e"||str === "i"||str === "o"||str === "u";
}
translatePigLatin("consonant");

7、搜索与替换

在这道题目中,我们需要写一个字符串的搜索与替换函数,它的返回值为完成替换后的新字符串。

这个函数接收的第一个参数为待替换的句子。

第二个参数为句中需要被替换的单词。

第三个参数为替换后的单词。

注意: 在更换原始单词时保留原始单词中第一个字符的大小写。 即如果传入的第二个参数为 Book,第三个参数为 dog,那么替换后的结果应为 Dog

function myReplace(str, before, after) {
  if(before[0] === before[0].toUpperCase()){
    after = after[0].toUpperCase() + after.slice(1);
  } else {
    after = after[0].toLowerCase() + after.slice(1);
  }
  return str.replace(before,after);
}

myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
myReplace("Let us go to the store", "store", "mall") 应返回 Let us go to the mall。

myReplace("He is Sleeping on the couch", "Sleeping", "sitting") 应返回 He is Sitting on the couch。

myReplace("I think we should look up there", "up", "Down") 应返回 I think we should look down there。

myReplace("This has a spellngi error", "spellngi", "spelling") 应返回 This has a spelling error。

myReplace("His name is Tom", "Tom", "john") 应返回 His name is John。

myReplace("Let us get back to more Coding", "Coding", "algorithms") 应返回 Let us get back to more Algorithms。

使用正则表达式:

function myReplace(str, before, after) {
  if (/^[A-Z]/.test(before)) {
    after = after[0].toUpperCase() + after.substring(1)
  } else {
    after = after[0].toLowerCase() + after.substring(1)
  }
  return str.replace(before, after);
}

8、DNA 配对

给出的 DNA 链上缺少配对元素。 请基于每个字符,获取与其配对的元素,并将结果作为二维数组返回。

DNA 的碱基对 有两种形式:一种是 A 与 T,一种是 C 与 G。 请为参数中给出的每个字符配对相应的碱基。

注意,参数中给出的字符应作为每个子数组中的第一个元素返回。

例如,传入 GCG 时,应返回 [["G", "C"], ["C","G"], ["G", "C"]]

字符和它的配对组成一个数组中,所有配对数组放在一个数组里。

function pairElement(str) {  var newArr = [];  for(let i = 0 ; i < str.length ; i++){    newArr.push([str[i],change(str[i])]);  }  return newArr;}function change(str){  switch(str){    case "A":      return "T";    case "T":      return "A";    case "G":      return "C";    case "C":      return "G";  }}pairElement("GCG");

9、寻找缺失的字母

在这道题目中,我们需要写一个函数,找出传入的字符串里缺失的字母并返回它。

如果所有字母都在传入的字符串范围内,返回 undefined

function fearNotLetter(str) {  for(let i = 0 ; i < str.length; i++){    let code = str.charCodeAt(i);    if(code !== str.charCodeAt(0) + i){      return String.fromCharCode(str.charCodeAt(0) + i);    }  }}fearNotLetter("abce");

10、集合排序

编写一个带有两个或更多数组的函数,并按原始提供的数组的顺序返回一个新的唯一值数组。

换句话说,所有数组中出现的所有值都应按其原始顺序包括在内,但最终数组中不得重复。

去重后的数字应按其出现在参数中的原始顺序排序,最终数组不应按数字大小进行排序。

uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) 应返回 [1, 3, 2, 5, 4]

uniteUnique([1, 2, 3], [5, 2, 1]) 应返回 [1, 2, 3, 5]

uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) 应返回 [1, 2, 3, 5, 4, 6, 7, 8]

function uniteUnique(arr) {  var newArr=[] ;  var args = Array.prototype.slice.call(arguments);  for(let i =0 ; i < args.length;i++){    newArr=newArr.concat(args[i].filter(function(item){      return newArr.indexOf(item) === -1;    }    ))  }  return newArr;}uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);

11、转换 HTML 字符实体

请将字符串中的 &<>"(双引号)和 '(单引号)转换为相应的 HTML 字符实体。

convertHTML("Dolce & Gabbana") 应返回 Dolce & Gabbana

convertHTML("Hamburgers < Pizza < Tacos") 应返回 Hamburgers < Pizza < Tacos

convertHTML("Sixty > twelve") 应返回 Sixty > twelve

convertHTML('Stuff in "quotation marks"') 应返回 Stuff in "quotation marks"

convertHTML("Schindler's List") 应返回 Schindler's List

convertHTML("<>") 应返回 <>

convertHTML("abc") 应该返回字符串 abc

function convertHTML(str) {  var a={        '&':'&amp;',        '<':'&lt;',        '>':'&gt;',        '"':'&quot;',        '\'':"&apos;"      };  return str.split("").map(x => a[x]||x).join("");}convertHTML("Dolce & Gabbana");


12、求斐波那契数列中的奇数之和

在这道题目中,我们需要写一个函数,参数为一个正整数 num,返回值为斐波那契数列中,小于或等于 num 的奇数之和。

斐波那契数列中,第一和第二个数字都是 1。 后面的每个数字由之前两数相加得出。 斐波那契数列的前六个数字分别为:1、1、2、3、5、8。

比如,sumFibs(10) 应该返回 10。 因为斐波那契数列中,比 10 小的数字只有 1、1、3、5。

function sumFibs(num) {  var arr = [];  var pre = 0;  var cur = 1;  while(cur <= num){    if(cur%2 !== 0){      arr.push(cur);    }    cur += pre;    pre = cur - pre;  }  return arr.reduce((x,y) => x+y);}sumFibs(4);

13、质数求和

质数(prime number)是大于 1 且仅可以被 1 和自己整除的数。 比如,2 就是一个质数,因为它只可以被 1 和 2(它本身)整除。 相反,4 不是质数,因为它可以被 1, 2 和 4 整除。

请完成 sumPrimes 方法,使其返回小于等于传入参数数字的所有质数之和。

function sumPrimes(num) {  var arr = [2];  for(let i = 3;i <= num ; i++){    let flag = true;    for(let j = 2 ; j< i;j++){      if(i%j === 0){        flag = false;      }    }    if(flag){      arr.push(i);    }  }  return arr.reduce((x,y) => x+y);}sumPrimes(10);

14找出数字范围内的最小公倍数

找到给定参数的最小公倍数,可以被这两个参数整除,也可以被指定范围内的所以整数整除。

注意,较小数不一定总是出现在数组的第一个元素。

例如,如果给定 1 和 3,找到 1 和 3 的最小公倍数,也可以被 1 到 3 之间的所有数字整除。 这里的答案将是 6。

/*思路:(1)在此之前要了解欧拉算法求最大公约数。简单的说,求两个数的最大公约数,用大数对小数求模,如果能被整除,则小数是这两个数的最大公约数。如果不能整除,就用小数对余数再次求模,循环此过程直到返回能除尽的那个除数。就是最大公约数。比如20和15,用20除以15余数为5,然后用15除以余数5,能够整除,所以返回出来的除数5为这两个数的最大公约数。(2)有了最大公约数,就可以求最小公倍数。最小公倍数的求法是:彼此之间的乘积除以最大公约数。因为是求几个连续自然数之间的公倍数,所以,求出前两个最小公倍数之后,用这个最小公倍数和下一个值比较。然后就得出了新的最小公倍数。主要用的是递归的思想。*/function smallestCommons(arr) {  arr=arr.sort(function(a,b){    return a-b;  });  function fun(m,n){    if(m%n===0) return n;    return fun(n,m%n);  }  var num=arr[0];  for(var i=arr[0]+1;i<=arr[1];i++){    num*=i/fun(num,i);  }  return num;}smallestCommons([1,5]);

15、根据参数删除数组元素

给定数组 arr,从数组的第一个元素开始,用函数 func 来检查数组的每个元素是否返回 true。 如果返回 false,就把这个元素删除。 持续执行删除操作,直到某个元素传入 func 时返回 true 为止。

然后在条件满足后返回数组的其余部分,否则, arr 应作为空数组返回。

function dropElements(arr, func) {
  var newArr = [];
  for(let i =0;i<arr.length;i++){
      if(func(arr[i])){
        newArr = arr.slice(i)
        return newArr;
      }
  }
  return newArr;
}

dropElements([1, 2, 3], function(n) {return n < 3; });

16、数组扁平化

嵌套数组扁平化成一维数组。 必须考虑到各种深度的嵌套层级。

steamrollArray([[["a"]], [["b"]]]) 应返回 ["a", "b"]

steamrollArray([1, [2], [3, [[4]]]]) 应返回 [1, 2, 3, 4]

steamrollArray([1, [], [3, [[4]]]]) 应返回 [1, 3, 4]

steamrollArray([1, {}, [3, [[4]]]]) 应返回 [1, {}, 3, 4]

代码中不应使用 Array.prototype.flat()Array.prototype.flatMap() 方法。

function steamrollArray(arr) {  var newArr = []  arr.map(item => {    if(Array.isArray(item)){      newArr = newArr.concat(steamrollArray(item));    } else {      newArr.push(item);    }  })    return newArr;}steamrollArray([1, [2], [3, [[4]]]]);

其他方案

function steamrollArray(arr) {
  const flattenedArray = [];
  // Loop over array contents
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      // Recursively flatten entries that are arrays
      //  and push into the flattenedArray
      flattenedArray.push(...steamrollArray(arr[i]));
    } else {
      // Copy contents that are not arrays
      flattenedArray.push(arr[i]);
    }
  }
  return flattenedArray;
};
function steamrollArray(arr) {
  const flat = [].concat(...arr);
  return flat.some(Array.isArray) ? steamrollArray(flat) : flat;
}

steamrollArray([1, [2], [3, [[4]]]]);

17、翻译二进制字符串

请实现一个函数,把传入的二进制字符串转换成英文句子。

二进制字符串会以空格分隔。

binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111") 应返回 Aren't bonfires fun!?

binaryAgent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001") 应返回 I love FreeCodeCamp!

function binaryAgent(str) {
  var arr = str.split(" ");
  var newArr = [];
  var newStr = '';
  for(let i = 0; i< arr.length;i++){
    newArr.push(parseInt(arr[i],2));
  }

  for(let i = 0;i<newArr.length;i++){
    newStr += String.fromCharCode(newArr[i]);
  }
  return newStr;
}

binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111");

18、一切都是True

检查谓词(第二个参数)在集合(第一个参数)的所有元素是否为 truthy。

换句话说,你将获得一个对象的数组集合。 如果数组中的每个对象里,pre 对应属性值均为 truthy,则返回 true。 否则,返回 false

JavaScript 中,如果一个值在 Boolean 的上下文中的执行结果为 true,那么我们称这个值是 truthy 的。

别忘了,你可以使用点号表示法或方括号表示法([])来访问对象的属性。

truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") 应返回 true

truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") 应返回 false

truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 0}, {"user": "Dipsy", "sex": "male", "age": 3}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age") 应返回 false

truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastForward", "onBoat": null}], "onBoat") 应返回 false

truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastForward", "onBoat": true}], "onBoat") 应返回 true

truthCheck([{"single": "yes"}], "single") 应返回 true

truthCheck([{"single": ""}, {"single": "double"}], "single") 应返回 false

truthCheck([{"single": "double"}, {"single": undefined}], "single") 应返回 false

truthCheck([{"single": "double"}, {"single": NaN}], "single") 应返回 false

function truthCheck(collection, pre) {
  for(let value of collection){
    if(!value[pre]){
      return false;
    }
  }
  return true;
}

truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex");

19、可选参数

创建一个将两个参数相加的函数。 如果只提供了一个参数,则返回一个需要一个参数并返回总和的函数。

比如,addTogether(2, 3) 应该返回 5。 而 addTogether(2) 应该返回一个函数。

调用这个返回的函数,为它传入一个值,会返回两个值的总和:

var sumTwoAnd = addTogether(2);

sumTwoAnd(3) 应返回 5

如果任一参数不是有效数字,则返回 undefined。

/*思路:这个其实就是call()方法。jquery的链式操作就是这样实现的。
函数链式操作原理:返回函数本身。当然也可以返回一个别的函数。
function show(str){
    alert(str);
    return show;//关键
}
show('abc')('bcd');
上述代码将弹出两个框,abc,和bcd。只要你想,可以无限地写下去。
你可以返回一个函数,那么下次操作时,得到的就是这个函数。*/
function addTogether(x) {
 if (arguments.length === 1 && typeof x === "number") {
   return function (y) { 
     if (typeof y === "number"){
       return x + y;
     }  
   }; 
 }else {
    if (typeof x !== "number"|| typeof arguments[1] !== "number") {
      return undefined;
    }
    return arguments[0] + arguments[1];
  } 
} 


addTogether(2,3);

20、创建一个人员对象

用以下方法填充对象构造函数:

getFirstName()
getLastName()
getFullName()
setFirstName(first)
setLastName(last)
setFullName(firstAndLast)

运行测试以查看每个方法的预期输出。 方法接收一个参数,因此必须要有一个参数,并且其类型应该为字符串。 这些方法必须是与对象交互的唯一可用方法。

var Person = function(firstAndLast) {
    var arr = firstAndLast.split(' '),
    firstName = arr[0],
          lastName = arr[1];
      this.getFirstName = function(){
        return firstName;
     };
    this.getLastName = function(){
        return lastName;
    };
    this.getFullName = function(){
        arr[0] = firstName;
        arr[1] = lastName;
        return arr.join(' ');
    };
    this.setFirstName = function(first){
         firstName = first;
    };
    this.setLastName = function(last){
        lastName = last;
    };
    this.setFullName = function(firstAndLast){
        arr = firstAndLast.split(' ');
        firstName = arr[0];
        lastName = arr[1];
    };
};
var bob = new Person('Bob Ross');
bob.getFullName();

21、计算轨道周期

在这道题目中,我们需要写一个计算天体轨道周期(单位是秒)的函数。

它接收一个对象数组参数 arr,对象中包含表示天体名称的 name 属性,及表示天体表面平均海拔的 avgAlt 属性。 就像这样:{name: 'name', avgAlt: avgAlt}

你可以在这条*的链接中找到轨道周期的计算公式:

最终的计算结果应取整到最接近的整数。 在这里计算地球的轨道周期。

地球半径为 6367.4447 公里,地球的 GM 值为 398600.4418 km 3 s -2 。

freeCodeCamp (JavaScript中级算法题)学习

function orbitalPeriod(arr) {
  const GM = 398600.4418;
  const earthRadius = 6367.4447;
  return arr.map(({ name, avgAlt }) => {
    const earth = earthRadius + avgAlt;
    const orbitalPeriod = Math.round(2 * Math.PI * Math.sqrt(Math.pow(earth, 3)/GM));
    return { name, orbitalPeriod };
  });
}

orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);

补充 JS中Math函数的常用方法

Math 是数学函数,但又属于对象数据类型 typeof Math => ‘object’
console.dir(Math) 查看Math的所有函数方法。

1,Math.abs() 获取绝对值

Math.abs(-12) = 12

2,Math.ceil() and Math.floor() 向上取整和向下取整

 console.log(Math.ceil(12.03));//13
 console.log(Math.ceil(12.92));//13
 console.log(Math.floor(12.3));//12
 console.log(Math.floor(12.9));//12

3,Math.round() 四舍五入
注意:正数时,包含5是向上取整,负数时包含5是向下取整。

1、Math.round(-16.3) = -16
2、Math.round(-16.5) = -16
3、Math.round(-16.51) = -17

4,Math.random() 取[0,1)的随机小数
案例1:获取[0,10]的随机整数

console.log(parseInt(Math.random()*10));//未包含10

console.log(parseInt(Math.random()*10+1));//包含10

案例2:获取[n,m]之间的随机整数

Math.round(Math.random()*(m-n)+n)

5,Math.max() and Max.min() 获取一组数据中的最大值和最小值

console.log(Math.max(10,1,9,100,200,45,78));
console.log(Math.min(10,1,9,100,200,45,78));

6,Math.PI 获取圆周率π 的值

console.log(Math.PI);

7,Math.pow() and Math.sqrt()

Math.pow()获取一个值的多少次幂
Math.sqrt()对数值开方

1.Math.pow(10,2) = 100;2.Math.sqrt(100) = 10;
上一篇:数组方法使用汇总


下一篇:freeCodeCamp “正向先行断言和负向先行断言“ 练习