[FreeCodeCamp-JavaScript]Intermediate Algorithm

在freecodecamp上学习js进行到中级算法部分了,这里记录一下,方便后面查看。
1.Sum All Numbers in a Range
我们会传递给你一个包含两个数字的数组。返回这两个数字和它们之间所有数字的和。
最小的数字并非总在最前面。

注意:

  • Math.min(val1[,val2,……,valn]),返回元素val1,val2,……valn中的最小值
  • Math.max(val1[,val2,……,valn]),返回元素val1,val2,……valn中的最大值

arr.reduce(callback,[initialValue])

  • callback执行数组中每个值的函数,包含四个参数(previousValue, currentValue, index, array)
  • previousValue指上一次调用回调返回的值,或者是提供的初始值(initialValue)
  • currentValue数组当前处理的元素
  • index当前元素在数组中的索引
  • array调用reduce的数组
  • initialValue可选,作为第一次调用callback第一个参数
  • [0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
    return previousValue + currentValue;
    });————–返回10=0+1+2+3+4
  • [0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
    return previousValue + currentValue;
    }, 10);返回20=10+0+1+2+3+4
  • 这个函数的使用暂时还不太熟,像这里提示中给出了这个函数,但我没用,后面要加强学习
function sumAll(arr) {
  //存储最后返回的值
  var num=0;
  //挑选出arr数组中较小的值,作为循环的起点
  var i=Math.min(arr[0],arr[1]);
  //挑选出arr数组中较大的值,作为循环的终点
  while(i<=Math.max(arr[0],arr[1])){
    num+=i;
    i++;
  } 
  return num;  
}

sumAll([1, 4]);

2.Diff Two Arrays
比较两个数组,然后返回一个新数组,该数组的元素为两个给定数组中所有独有的数组元素。换言之,返回两个数组的差异。

function diff(arr1, arr2) {
  var newArr = [];
  // Same, same; but different.
  //在arr2中挑出arr1中没有的元素
  var a1=arr1.filter(function(item,index,array){
    return (arr2.indexOf(item)<0);
  });
  //在arr1中挑出arr2中没有的元素
  var a2=arr2.filter(function(item,index,array){
    return (arr1.indexOf(item)<0);
  });
  //合并数组中各自独有的部分a1和a2
  newArr=a1.concat(a2); 
  return newArr;
}

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

3.Roman Numeral Converter
将给定的数字转换成罗马数字。
所有返回的 罗马数字 都应该是大写形式。

分析:

  • 这里首先要定义好数字和罗马数字之间的对应数组romanMatrix
  • 采用递归的方法
  • 这个题目比较有亮点,后期还需要复习
//定义部分数字和罗马数字之间的对应关系数组
var romanMatrix=[
  [1000,'M'],
  [900,'CM'],
  [500,'D'],
  [400,'DC'],
  [100,'C'],
  [90, 'XC'],
  [50, 'L'],
  [40, 'XL'],
  [10, 'X'],
  [9, 'IX'],
  [5, 'V'],
  [4, 'IV'],
  [1, 'I']
];
function convert(num) {
  //给定数字为0时,返回空值
  if(num===0)
    return '';
  //递归找出给定数字对应的罗马数字
  for(var i=0;i<romanMatrix.length;i++){
    if(num>=romanMatrix[i][0])
      return romanMatrix[i][1]+convert(num-romanMatrix[i][0]);
  }
}

convert(88);

4.Where art thou
写一个 function,它遍历一个对象数组(第一个参数)并返回一个包含相匹配的属性-值对(第二个参数)的所有对象的数组。如果返回的数组中包含 source 对象的属性-值对,那么此对象的每一个属性-值对都必须存在于 collection 的对象中。
例如,如果第一个参数是 [{ first: “Romeo”, last: “Montague” }, { first: “Mercutio”, last: null }, { first: “Tybalt”, last: “Capulet” }],第二个参数是 { last: “Capulet” },那么你必须从数组(第一个参数)返回其中的第三个对象,因为它包含了作为第二个参数传递的属性-值对。
分析:

  • 先循环保存source中key值和对应value值
  • 再在collection中遍历比较collection[i]中对应key值和value值是否与source中的相等
  • 若相等,就push到arr数组中,最终返回arr
function where(collection, source) {
  var arr = [];
  // What's in a name?
  //循环保存source中key值
  var key_val="";
  //循环保存source中key值对应value,即source[key]
  var value_val="";
  //循环取出source中key和value
  for(var key in source){
    key_val=key;
    value_val=source[key];
  }
  //循环比较collection中是否包含value=source[key]
  for(var i=0;i<collection.length;i++){
    for(var key in collection[i]){
      if(key_val==key && value_val==collection[i][key])
        //如果包含,push入arr数组尾
        arr.push(collection[i]);
    }
  }
  return arr;
}

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

5.Search and Replace
使用给定的参数对句子执行一次查找和替换,然后返回新句子。
第一个参数是将要对其执行查找和替换的句子。
第二个参数是将被替换掉的单词(替换前的单词)。
第三个参数用于替换第二个参数(替换后的单词)。
注意:替换时保持原单词的大小写。例如,如果你想用单词 “dog” 替换单词 “Book” ,你应该替换成 “Dog”。

//判断字符串str中首字符是否大写
function isFirstUpper(str){
  if(str.charAt(0)==str.charAt(0).toUpperCase())
    return true;
  else
    return false;
}
//将字符串str中首字符替换成大写形式
function firstToUpper(str){
  return str.replace(str.charAt(0),str.charAt(0).toUpperCase());
}
function myReplace(str, before, after) {  
  //如果即将被替换的单词before中首字符为大写形式
  //则将替换before的单词after首字符替换成大写形式
  if(isFirstUpper(before)){
    after=firstToUpper(after);
  }
  //将str中目标单词before用after替换
  str=str.replace(before,after);
  return str;
}

myReplace("A quick brown fox Jumped over the lazy dog", "Jumped", "leaped");

6.Pig Latin
把指定的字符串翻译成 pig latin。
Pig Latin 把一个英文单词的第一个辅音或辅音丛(consonant cluster)移到词尾,然后加上后缀 “ay”。
如果单词以元音开始,你只需要在词尾添加 “way” 就可以了。

function translate(str) {
  //定义元音字母组成的字符数组
  var vowel=['a','e','i','o','e'];
  //保存str中开头的辅音丛的长度
  var i=0;
  var newstr=str;
  //循环求出字符串str中开头的辅音丛的长度i
  while(i<str.length){
    //通过arr.indexOf判断字符是否是元音
    //如果元音数组vowel中不包含该字符,则为辅音;
    //否则str中首字符即为元音,直接退出循环
    if(vowel.indexOf(str[i])==-1){
      i++;
    }
    else{
      break;
    }
  }
  //如果str开头即为元音,则直接在字符尾部加上way
  if(i==0){
    newstr=newstr+"way";  
  }
  //如果str开头存在辅音丛,则将str首的辅音丛直接移到字符串尾,并加上ay
  else{
    newstr=newstr.substr(i)+newstr.substr(0,i)+"ay";   
  }
  return newstr;
}

translate("california");

7.DNA Pairing
DNA 链缺少配对的碱基。依据每一个碱基,为其找到配对的碱基,然后将结果作为第二个数组返回。
Base pairs(碱基对) 是一对 AT 和 CG,为给定的字母匹配缺失的碱基。
在每一个数组中将给定的字母作为第一个碱基返回。
例如,对于输入的 GCG,相应地返回 [[“G”, “C”], [“C”,”G”],[“G”, “C”]]
字母和与之配对的字母在一个数组内,然后所有数组再被组织起来封装进一个数组。

function pair(str) {
  //以碱基对的配对关系定义map键值对
  var map={
    'A':'T',
    'T':'A',
    "G":'C',
    'C':'G'
   };
  var arr=[];
  var i=0;
  var len=str.length;
  while(i<len){
    //循环依次从map中取出与键(str的各个字符)相对于的值value
    var value=map[str[i].toUpperCase()];
    //将key和value组成的数组push到arr数组中
    arr.push([str[i],value]);
    i++;
    }      
  return arr;
}

pair("GCG");

8.Missing letters
从传递进来的字母序列中找到缺失的字母并返回它。
如果所有字母都在序列中,返回 undefined。

function fearNotLetter(str) {
  var len=str.length;
  //str中第一个字符的Unicode值
  var start=str.charCodeAt(0);
  //str中最后一个字符的Unicode值
  var end=str.charCodeAt(len-1);
  var arr=[];
  var j=0;
  for(var i=start;i<=end,j<len;i++,j++){
    //循环遍历,如果str中字符不等于Unicode值i对应的字符
    //说明str中该字符缺失,push入str数组中
    //注意:str中数组下标j要保持不变,继续与下一个Unicode值所对应的字符比较
    if(str[j]!=String.fromCharCode(i)){
      arr.push(String.fromCharCode(i)); 
      //为了保持下标j不变,这里要减1,因为循环会自动加1
      j--;
    }      
  }
  if(arr.length===0)
    return undefined;
  else
    //return arr.toString();
    return arr.join('');  
}

fearNotLetter("abcdefgho");

9.Boo who
检查一个值是否是基本布尔类型,并返回 true 或 false。
基本布尔类型即 true 和 false。
注意:
typeof operand

  • typeof操作符返回操作数的类型(字符串)
  • operand是一个表达式,表示对象或原始值,返回其类型
  • 例如:typeof 3.14 === ‘number’;typeof “bla” === ‘string’;typeof true === ‘boolean’;
  • typeof new String(“abc”) === ‘object’;typeof Math.sin === ‘function’;
  • typeof undefined === ‘undefined’;typeof [1, 2, 4] === ‘object’;
function boo(bool) {
  // What is the new fad diet for ghost developers? The Boolean.
  //typeof bool 返回bool的类型,即boolean
  return typeof bool==='boolean';
}

boo(1);

10.Sorted Union
写一个 function,传入两个或两个以上的数组,返回一个以给定的原始数组排序的不包含重复值的新数组。
换句话说,所有数组中的所有值都应该以原始顺序被包含在内,但是在最终的数组中不包含重复值。
非重复的数字应该以它们原始的顺序排序,但最终的数组不应该以数字顺序排序。
总结:

  • arguments很神奇,可以直接检索到函数中传递的参数个数
  • arr.indexOf(char),功能上类似于java中的contains函数
  • 可以用于查找arr数组中是否包含某个char元素,有就返回对应索引;没有就返回-1
function unite() {
  var arr=[];
  //unite中参数总数目(即数组个数)
  var len=arguments.length;
  //控制遍历哪个数组(arguments[i],i可取0~len-1)
  var i=0;  
  while(i<len){
    //控制遍历的数组arguments[i]中元素下标
    var j=0;
    while(j<arguments[i].length){
      //如果arr中没有索引为i的数组参数中的索引为j的元素
      //将其push到arr中
      if(arr.indexOf(arguments[i][j])==-1)
         arr.push(arguments[i][j]);
      j++;
    }
    i++;   
  }  
  return arr;
}

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

11.Convert HTML Entities
将字符串中的字符 &、<、>、” (双引号), 以及 ’ (单引号)转换为它们对应的 HTML 实体。
注意:

  • 正则表达式中,描述”、’等需要加上转义符号\
  • &对应html实体为&amp;
  • <对应html实体为&lt;
  • >对应html实体为&gt;
  • “对应html实体为&quot;
  • ‘对应html实体为&apos;
function convert(str) {
  // &colon;&rpar;  
  return str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;").replace(/\'/g,"&apos;");
}

convert("Dolce & Gabbana");

12.Spinal Tap Case
将字符串转换为 spinal case。Spinal case 是 all-lowercase-words-joined-by-dashes 这种形式的,也就是以连字符连接所有小写单词。
分析:

  • 需要转换的字符串格式可以归为两类:
  • 第一类是利用空格、下划线等符号分解命名(以下称符号类型)str.split(/\W|_/)
  • 第二类是驼峰命名法(以下称驼峰类型)
  • 首先把这两种字符串类型分开,可以将字符串的按照第一种符号类型分解,如果str.split(/\W|_/).length==1(即分解后的数组长度为1),就说明当前字符串是第二种驼峰类型
function spinalCase(str) {
  // "It's such a fine line between stupid, and clever."
  // --David St. Hubbins
  //判断如果是驼峰命名法
  //\W 匹配任意不是基本拉丁字母表中单词(字母数字下划线)字符的字符
  //|_ 由于基本拉丁字母表中包含下划线,这里下划线要单独判断
  if(str.split(/\W|_/).length==1){
      for(var i=0;i<str.length;i++){
      //对str中每个字符遍历判断,找到驼峰命名中的大写字母(/[A-Z]/.test()),即为单词的分界处
      if(/[A-Z]/.test(str[i])){
      //直接用-+大写字母对应小写字母替换大写字母处即可
      str=str.replace(str[i],"-"+str[i].toLowerCase());
  }
  }         
 }
  //采用其他字符和下划线为单词分界的情形
  //直接转换成小写,再用正则分割,最后以-连接起来即可
 else{
   str=str.toLowerCase().split(/\W|_/).join("-");
 }  
  return str;
}

spinalCase('thisIsSpinalTap');

13.Sum All Odd Fibonacci Numbers
返回所有小于传入数值的斐波那契数列中的奇数之和,如果传入的数值是斐波那契数,那么它也应该参与求和。
斐波那契数列中的前几个数字是 1、1、2、3、5 和 8,随后的每一个数字都是前两个数字之和。
例如,向 function 传入 4 应该返回 5,因为斐波那契数列中所有小于 4 的奇数是 1、1、3。
分析:
此题不需要真实现斐波拉契算法,只需要按照算法挑选出其中的奇数项,并求和即可
斐波拉契数的定义:F(n)=F(n-1)+F(n-2)+…+F(1),即提取小于等于传入值的斐波拉契数列中奇数项并相加即可

function sumFibs(num) {
  //a、b、c用来进行斐波拉契算法,sum统计最终的和
  var a=0,b=0,c=1,sum=0;
  //只要c<=num,就进行斐波拉契算法循环统计sum
  while(c<=num){
    //如果c是斐波拉契中的奇数项
    if(c%2==1)
      sum+=c;
    //控制斐波拉契循环进行,该算法中每一个数字都是前两个数字之和
    a=b;
    b=c;
    c=a+b;
  }
  return sum;
}

sumFibs(4);

14.Sum All Primes
求小于等于给定数值的质数之和。
只有 1 和它本身两个约数的数叫质数。例如,2 是质数,因为它只能被 1 和 2 整除。1 不是质数,因为它只能被自身整除。
给定的数不一定是质数。
注意:
for(var i=2;i<=Math.sqrt(num);i++)这里进行了部分优化,可以减少循环次数:
判断一个数是否是质数,只需要判断是否能被2~√num整除即可。

//判断num是否是质数
function isPrime(num){
  //标记是否是质数,初始值是true
  var flag=true;
  //质数:只能被1和本身整除
  //如果num可以整除2~Math.sqrt(num)中的任意一个数,则num不是质数,改变标记flag,并终止循环
  for(var i=2;i<=Math.sqrt(num);i++){
    if(num%i===0)
    {
      flag=false;
      break;
    }
  }
  return flag;
}

function sumPrimes(num) {
  var sum=0;
  //循环判断i=2~num是否是质数,如果是,与sum求和
  for(var i=2;i<=num;i++){
    if(isPrime(i))
      sum+=i;
  }
  return sum;
}

sumPrimes(10);

15.Smallest Common Multiple
找出能被两个给定参数和它们之间的连续数字整除的最小公倍数。
范围是两个数字构成的数组,两个数字不一定按数字顺序排序。
例如对 1 和 3 —— 找出能被 1 和 3 和它们之间所有数字整除的最小公倍数。
注意:
这里涉及到经典算法:求最大公约数gcd(greatest common divisor)和最小公倍数scm(smallest common multiple)
gcd(最大公约数)算法过程(欧几里德算法/辗转相除法)
有两整数a和b:
① a%b得余数c,即c=a%b
② 若c=0,则b即为两数的最大公约数
③ 若c≠0,则a=b,b=c,再回去执行①
scm算法(最小公倍数算法)
最小公倍数=两整数的乘积÷最大公约数,即scm=sqrt(a*b)/gcd(a,b)

//求val1和val2的最大公约数(greatest common divisor)
//欧几里德算法(辗转相除法)
function gcd(val1,val2){
  if(val1%val2===0)
    return val2;
  else
    return gcd(val2,val1%val2);
}

function smallestCommons(arr) {
  //将arr按升序排序
  arr=arr.sort(function(a,b){
    return a-b;
  });  
  //求a和b的最小公倍数scm(smallest common multiple)
  //scm=abs(a*b)/gcd(a,b)
  var val=arr[0];
  //这里求多个数的最小公倍数:先求出两个数的scm1,再求scm1与第三个数的scm2……依次循环
  for(var i=arr[0]+1;i<=arr[1];i++){
    val *=i/gcd(val,i);
  }
  return val;
}

smallestCommons([1,5]);

16.Finders Keepers
写一个 function,它浏览数组(第一个参数)并返回数组中第一个通过某种方法(第二个参数)验证的元素。
注意:arr.filter(func),返回arr中满足函数func的值

function find(arr, func) {
  //数组result中保存arr数组中满足func函数的值
  var result=arr.filter(func);
  //如果result数组中有值存在(即arr中有满足func函数的值),则返回数组中第一个元素
  if(result.length)
    return result[0];
  else
    return undefined;
}

find([1, 3, 5, 9], function(num) { return num % 2 === 0; });

17.Drop it
Drop the elements of an array (first argument), starting from the front, until the predicate (second argument) returns true.
给定两个参数,第一个参数是一个数组,第二个参数是一个测试函数,算法需要以数组形式弹出满足测试函数的数组元素。
注意:循环过程中,因为shift操作会直接改变数组arr,所以数组arr的长度len在不断变化,每次都要重新计算

function drop(arr, func) {
      // Drop them elements.
      //临时保存数组arr中首元素
      var tmp;
      //注意这里每一次循环都需要重新取得数组arr的长度len,因为数组通过shift等操作不断在变化
      for(var i=0,len=arr.length;i<len;i++){
        //提取出数组arr中的第一个元素,此时数组会改变(索引、长度均会改变)
          tmp = arr.shift();
        //如果数组中首元素满足func函数,停止抛弃不合条件的元素的动作
          if(func(tmp)){
            //将满足条件的元素再插入数组首位,此时数组也会发生变化
            arr.unshift(tmp);
            break;
          }
      }      
      return arr;
}

drop([1, 2, 3, 4], function(n) {return n > 5;});

18.Steamroller
Flatten a nested array. You must account for varying levels of nesting.
对嵌套的数组进行扁平化处理。你必须考虑到不同层级的嵌套。
注意:
arr.concat(value1[,value2,valueN])

  • value2~valueN可选,代表需要与数组arr合并的数组非数组值
  • 返回一个新数组,不修改原数组arr

Array.isArray(arr)
- 判断arr是否是一个数组
- 如果arr是数组则返回true,否则false

function steamroller(arr) {
  //result数组保存最后的结果数组
  var result = [];
  for(var i = 0; i < arr.length; i ++) {
    //如果arr[i]是数组,递归求出arr[i]的扁平化数组steamroller(arr[i]),与result数组拼接
    if(Array.isArray(arr[i])) {
      result = result.concat(steamroller(arr[i]));
    } 
    //如果arr[i]不是数组,直接push到result数组
    else {
      result.push(arr[i]);
    }
  }
  return result;
}

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

19.Binary Agents
Return an English translated sentence of the passed binary string.
传入二进制字符串,翻译成英语句子并返回。
二进制字符串是以空格分隔的。
注意:
parseInt(string, radix) 将给定的字符串以指定基数radix解析成为整数
这里使用parseInt(code[i], 2),将code[i]以基数2(即将其当做二进制串解析)解析为整数

function binaryAgent(str) {
  //将二进制串str用空格分割成数组code
  var code=str.split(' ');
  //保存最终字符串数组
  var result='';
  for(var i=0;i<code.length;i++){
    //将数组code[i]中二进制数通过parseInt(string, radix)转换成整数
    //再通过函数String.fromCharCode(整数)得出对应字符
    result+=String.fromCharCode(parseInt(code[i], 2));
  }
  return result;
}

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

20.
Check if the predicate (second argument) is truthy on all elements of a collection (first argument).
所有的东西都是真的!
完善编辑器中的every函数,如果集合(collection)中的所有对象都存在对应的属性(pre),并且属性(pre)对应的值为真。函数返回ture。反之,返回false。

function every(collection,pre){
  for(var i=0;i<collection.length;i++){
    //如果collection[i][pre]为假或collection[i]不存在pre属性
    if(!collection[i][pre]){
      return false;
    }
  }
  return true;
}

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

21.Arguments Optional
创建一个计算两个参数之和的 function。如果只有一个参数,则返回一个 function,该 function 请求一个参数然后返回求和的结果。
例如,add(2, 3) 应该返回 5,而 add(2) 应该返回一个 function。
调用这个有一个参数的返回的 function,返回求和的结果:
var sumTwoAnd = add(2);
sumTwoAnd(3) 返回 5。
如果两个参数都不是有效的数字,则返回 undefined。
注意:typeof 返回对象的类型(js总共有5种类型:null、number、string、boolean、undefined)

function add() {
  //typeof 返回对象的类型(总共有5种类型:null、number、string、boolean、undefined)
  //arguments[i]返回函数add中传入的dii个参数
  if(typeof arguments[0]=="number" && typeof arguments[1]=="number"){
    return arguments[0]+arguments[1];
  }
  else if(arguments.length==1 && typeof arguments[0]=="number"){
    var x=arguments[0];
    //如果只有一个数字型参数x,返回x和后面捕捉到的任意一个数字型参数y之和
    return function(y){
      if(typeof y =="number"){
        return x+y;
      }
    };
  }
}

add(2,3);
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值