算法中级——来源freecodecamp

算法中级——freecodecamp

    • 范围内的数字求和
    • 区分两个数组
    • 瞄准和消灭
    • 罗密欧与朱丽叶
    • 短线连接格式
    • 儿童黑话
    • 搜索和替换
    • DNA 配对
    • 丢失的字母
    • 集合排序
    • 转换HTML实体
    • 求斐波那契数组中的奇数之和
    • 对所有素数求和
    • 最小公倍数
    • 欧几里得算法gcd算法寻找最大公因数
    • 找出两个数的最小公倍数
    • 放弃
    • 扁平化
    • 二进制转化
    • 真假值判断
    • 可选参数
    • 构造一个 Person 类
    • 绘制碎片图

范围内的数字求和

给出一个含有两个数字的数组,我们需要写一个函数,让它返回这两个数字间所有数字(包含这两个数字)的总和。

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

  • 方法一:找出最大最小值,然后从小+1直到最大数。
function sumAll(arr) {
    var max = Math.max(arr[0], arr[1]);
    var min = Math.min(arr[0], arr[1]);
    var temp = 0;
    for (var i=min; i <= max; i++){
        temp += i;
    }
  return(temp);
}

sumAll([1, 4]);

用ES6扩展运算符简化代码。

function sumAll(arr) {
    var sum = 0;
    for (var i = Math.min(...arr); i <= Math.max(...arr); i++){
        sum += i;
    }
  return sum;
}

sumAll([1, 4]);
  • 方法二:运用等差数列求和。和=(首项+末项)/2*项数。
function sumAll(arr) {
  // Buckle up everything to one!

  // Using ES6 arrow function (one-liner)
  var sortedArr = arr.sort((a,b) => a-b);
  var firstNum = arr[0];
  var lastNum = arr[1];
  // Using Arithmetic Progression summing formula

  var sum = (lastNum - firstNum + 1) * (firstNum + lastNum) / 2;
  return sum;
}

区分两个数组

在这道题目中,我们需要写一个函数,比较两个数组,返回一个新的数组。这个新数组需要包含传入的两个数组所有元素中,仅在其中一个数组里出现的元素。如果某个元素同时出现在两个数组中,则不应包含在返回的数组里。换言之,我们需要返回这两个数组的对称差。

  • 方法一:首先遍历arr1中的值看是否在arr2中存在,不在则添加进新数组;再遍历arr2中的值看是否在arr1中存在。
function diffArray(arr1, arr2) {
  var newArr = [];
  // 这是一个党异伐同的过程
  for(let i=0;i<arr1.length;i++){
    if(arr2.indexOf(arr1[i]) == -1){
      newArr.push(arr1[i]);
    }
  }
  for(let j=0;j<arr2.length;j++){
    if(arr1.indexOf(arr2[j]) == -1){
      newArr.push(arr2[j]);
    }
  }
  return newArr;
}

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

封装一下函数

    function diffArray(arr1, arr2) {
      var newArr = [];

      function onlyInFirst(first, second) {
      // Looping through an array to find elements that don't exist in another array
    for (var i=0;i<first.length;i++) {
      if (second.indexOf(first[i]) === -1) {
        // Pushing the elements unique to first to newArr
        newArr.push(first[i]);
      }
    }
  }

  onlyInFirst(arr1, arr2);
  onlyInFirst(arr2, arr1);

  return newArr;
}

diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
function diffArray(arr1, arr2) {
  return [
    ...diff(arr1, arr2),
    ...diff(arr2, arr1)
  ]
  
  function diff(a, b) {
    return a.filter(item => b.indexOf(item) === -1);
  }
}
  • 方法二:将两数组合并为一个新的数组,过滤其中重复的数。
function diffArray(arr1, arr2) {
      return arr1
        .concat(arr2)
        .filter(
            item => !arr1.includes(item) || !arr2.includes(item)
        )
    }

    diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
function diffArray(arr1, arr2) {
    return arr1
      .filter(el => !arr2.includes(el))
      .concat(
        arr2.filter(el => !arr1.includes(el))
      )
}

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

瞄准和消灭

在这道题目中,我们要写一个叫destroyer的函数。传给它的第一个参数是数组,我们称他为初始数组。后续的参数数量是不确定的,可能有一个或多个。你需要做的是,从初始数组中移除所有与后续参数相等的元素,并返回移除元素后的数组。
在这道题目中,主要要学会将类数组转化为数组,主要利用Array.prototype.slice.call(arguments)或者Array.from(arguments)方法。

function destroyer(arr) {
  var args = Array.prototype.slice.call(arguments);

  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < args.length; j++) {
      if (arr[i] === args[j]) {
        delete arr[i];
      }
    }
  }
  return arr.filter(Boolean);
}
function destroyer(arr) {
  var args = Array.from(arguments).slice(1);
  return arr.filter(function(val) {
    return !args.includes(val);
  });
}
const destroyer = (arr, ...args) => arr.filter(i => !args.includes(i));

罗密欧与朱丽叶

在这道题目中,我们要写一个函数,它接收两个参数:第一个参数是对象数组,第二个参数是一个对象。我们需要从对象数组中找出与第二个参数相等或包含第二个参数的所有对象,并以对象数组的形式返回。其中,相等的意思是原数组中的对象与第二个参数中对象的所有键值对完全相等;包含的意思是只要第二个参数中对象的所有键存在于原数组对象中,且它们对应的值相同即可。

比如,如果第一个参数是[{ first: “Romeo”, last: “Montague” }, { first: “Mercutio”, last: null }, { first: “Tybalt”, last: “Capulet” }],第二个参数是{ last: “Capulet” }。那么你需要以对象数组的形式返回第一个参数中的第三个元素,因为它包含第二个参数中定义的键last,且对应的值"Capulet"相同.

function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function (obj) {
    for(var i = 0; i < srcKeys.length; i++) {
      if(!obj.hasOwnProperty(srcKeys[i]) || obj[srcKeys[i]] !== source[srcKeys[i]]) {
        return false;
      }
    }
    return true;
  });
}

// test here
whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  return collection.filter(function (obj) {
    return srcKeys.every(function (key) {
      return obj.hasOwnProperty(key) && obj[key] === source[key];
    });
  });
}

// test here
whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function (obj) {
    return srcKeys
      .map(function(key) {
        return obj.hasOwnProperty(key) && obj[key] === source[key];
      })
      .reduce(function(a, b) {
        return a && b;
      });
  });
}

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

短线连接格式

在这道题目中,我们需要写一个函数,把一个字符串转换为“短线连接格式”。短线连接格式的意思是,所有字母都是小写,且用-连接。比如,对于Hello World,应该转换为hello-world;对于I love_Javascript-VeryMuch,应该转换为i-love-javascript-very-much。

function spinalCase(str) {
  // Create a variable for the white space and underscores.
  var regex = /\s+|_+/g;

  // Replace low-upper case to low-space-uppercase
  str = str.replace(/([a-z])([A-Z])/g, '$1 $2');

  // Replace space and underscore with -
  return str.replace(regex, '-').toLowerCase();
}

// test here
spinalCase('This Is Spinal Tap');
function spinalCase(str) {
  // "It's such a fine line between stupid, and clever."
  // --David St. Hubbins

  return str.split(/\s|_|(?=[A-Z])/).join('-').toLowerCase()
}

补充正则小知识:
(?=[A-Z])表示什么后面以大写字母开始。

儿童黑话

在这道题目中,我们需要写一个函数,把传入的字符串翻译成“儿童黑话”。

儿童黑话的基本转换规则很简单,只需要把一个英文单词的第一个辅音字母或第一组辅音从移到单词的结尾,并在后面加上ay即可。在英语中,字母 a、e、i、o、u 为元音,其余的字母均为辅音。辅音从的意思是连续的多个辅音字母。

额外地,如果单词本身是以元音开头的,那只需要在结尾加上way。

在本题中,传入的单词一定会是英文单词,且所有字母均为小写。

  // Create variables to be used
  var pigLatin = '';
  var regex = /[aeiou]/gi;

  // Check if the first character is a vowel
  if (str[0].match(regex)) {
    pigLatin = str + 'way';

  } else if(str.match(regex) === null) {
    // Check if the string contains only consonants
    pigLatin = str + 'ay';
  } else {

    // Find how many consonants before the first vowel.
    var vowelIndice = str.indexOf(str.match(regex)[0]);

    // Take the string from the first vowel to the last char
    // then add the consonants that were previously omitted and add the ending.
    pigLatin = str.substr(vowelIndice) + str.substr(0, vowelIndice) + 'ay';
  }

  return pigLatin;
}

// test here
translatePigLatin("consonant");

搜索和替换

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

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

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

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

注意:
你需要保留被替换单词首字母的大小写格式。即如果传入的第二个参数为 “Book”,第三个参数为 “dog”,那么替换后的结果应为 “Dog”.

function myReplace(str, before, after) {
  // Find index where before is on string
  var index = str.indexOf(before);
  // Check to see if the first letter is uppercase or not
  if (str[index] === str[index].toUpperCase()) {
    // Change the after word to be capitalized before we use it.
    after = after.charAt(0).toUpperCase() + after.slice(1);
  }
  // Now replace the original str with the edited one.
  str = str.replace(before, after);

  return str;
}

// test here
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
function myReplace(str, before, after) {
//Create a regular expression object
  var re = new RegExp(before,"gi");
//Check whether the first letter is uppercase or not
  if(/[A-Z]/.test(before[0])){
  //Change the word to be capitalized
    after = after.charAt(0).toUpperCase()+after.slice(1);
     }
     //Replace the original word with new one
  var  newStr =  str.replace(re,after);

 return newStr;
}

// test here
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

注意:首字母大写的一个方法

arr[i]=arr[i].charAt(0).toUpperCase()+arr[i].slice(1);

DNA 配对

在这道题目中,我们需要写一个函数,为 DNA 中的碱基配对。这个函数只接收一个表示碱基的字符串为参数,最后返回完成配对的二维数组。

碱基对 由一对碱基组成。碱基有四种,分别为 A(腺嘌呤)、T(胸腺嘧啶)、G(鸟嘌呤)和 C(胞嘧啶)。配对原则是:A 与 T 配对,C 与 G 配对。我们需要根据这个原则对传入的所有碱基进行配对。

对于每个传入的碱基,我们应采用数组的形式展示配对结果。其中,传入的碱基需要作为数组的第一个元素出现。最终返回的数组中应当包含参数中每一个碱基的配对结果。

比如,传入的参数是 GCG,那么函数的返回值应为 [[“G”, “C”], [“C”,“G”],[“G”, “C”]]

  • 方法一:遍历字符串,挨个替换。
function pairElement(str) {
  var paired = [];
  var search = function(char){
    switch(char){
      case 'A':
        paired.push(['A', 'T']);
        break;
      case 'T':
        paired.push(['T', 'A']);
        break;
      case 'C':
        paired.push(['C', 'G']);
        break;
      case 'G':
        paired.push(['G', 'C']);
        break;
    }
  }
  for (var i = 0; i < str.length; i++) {
        search(str[i]);
  }

  return paired;
}

pairElement("GCG");
  • 方法二:使用类似哈希表的方法,来查找对应的匹配。
function pairElement(str) {
  var pairs = {
    "A":["A","T"],
    "T":["T","A"],
    "G":["G","C"],
    "C":["C","G"]
  }
  var arr = str.split('');
  return arr.map(x=>pairs[x]);
}

pairElement("GCG");

丢失的字母

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

判断缺失的依据是字母顺序,比如 abcdfg 中缺失了 e。而 abcdef 中就没有字母缺失,此时我们需要返回undefined。

function fearNotLetter(str) {

  for(var i = 0; i < str.length; i++) {
    /* code of current character */
    var code = str.charCodeAt(i);

    /* if code of current character is not equal to first character + no of iteration
    hence character has been escaped */
    if (code !== str.charCodeAt(0) + i) {

      /* if current character has escaped one character find previous char and return */
      return String.fromCharCode(code - 1);
    }  
  }
  return undefined;
}

// test here
fearNotLetter("abce");
// Adding this solution for the sake of avoiding using 'for' and 'while' loops.
// See the explanation for reference as to why. It's worth the effort.

function fearNotLetter(str) {
  var compare = str.charCodeAt(0), missing;

  str.split('').map(function(letter,index) {
    if (str.charCodeAt(index) == compare) {
      ++compare;
    } else {
      missing = String.fromCharCode(compare);
    }
  });

  return missing;
}

// test here
fearNotLetter("abce");
function fearNotLetter(str) {
  for (let i = 1; i < str.length; ++i) {
    if (str.charCodeAt(i) - str.charCodeAt(i-1) > 1) {
      return String.fromCharCode(str.charCodeAt(i - 1) + 1);
    }
  }
}

集合排序

在这道题目中,我们需要写一个函数,它接收两个或多个数组为参数。我们需要对这些数组中所有元素进行去除重复元素的处理,并以数组的形式返回去重结果。

需要注意的是,结果数组中的元素顺序必须与其传入的顺序保持一致。

function uniteUnique(arr1, arr2, arr3) {
  // Creates an empty array to store our final result.
  var finalArray = [];

  // Loop through the arguments object to truly made the program work with two or more arrays
  // instead of 3.
  for (var i = 0; i < arguments.length; i++) {
    var arrayArguments = arguments[i];

    // Loops through the array at hand
    for (var j = 0; j < arrayArguments.length; j++) {
      var indexValue = arrayArguments[j];

      // Checks if the value is already on the final array.
      if (finalArray.indexOf(indexValue) < 0) {
        finalArray.push(indexValue);
      }
    }
  }

  return finalArray;
}

// test here
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
function uniteUnique(arr) {
  var args = [...arguments];
  var result = [];
  for(var i = 0; i < args.length; i++) {
    for(var j = 0; j < args[i].length; j++) {
       if(!result.includes(args[i][j])) {
        result.push(args[i][j]);
      }
    }
  }
  return result;
}

uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
function uniteUnique(arr1, arr2, arr3) {
 var newArr;
 //Convert the arguments object into an array
  var args = Array.prototype.slice.call(arguments);
  //Use reduce function to flatten the array
  newArr = args.reduce(function(arrA,arrB){
  //Apply filter to remove the duplicate elements in the array
    return arrA.concat(arrB.filter(function(i){
      return arrA.indexOf(i) === -1;
    }));
  });

   return newArr;                    
}

// test here
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
function uniteUnique() {
  var concatArr = [];
  var i = 0;
  while (arguments[i]){
    concatArr = concatArr.concat(arguments[i]); i++;
  }
  uniqueArray = concatArr.filter(function(item, pos) {
    return concatArr.indexOf(item) == pos;
  });
  return uniqueArray;
}

// test here
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
function uniteUnique(...arrays) {

  //make an array out of the given arrays and flatten it (using the spread operator)
  const flatArray = [].concat(...arrays);

  // create a Set which clears any duplicates since it's a regulat set and not a multiset
  return [...new Set(flatArray)];
}

// test here
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);

转换HTML实体

在这道题目中,我们需要写一个转换 HTML entity 的函数。需要转换的 HTML entity 有&、<、>、"(双引号)和’(单引号)。转换的规则你可以在 W3C 官网找到。

function convertHTML(str) {
  // Split by character to avoid problems.

  var temp = str.split('');

  // Since we are only checking for a few HTML elements I used a switch

  for (var i = 0; i < temp.length; i++) {
    switch (temp[i]) {
      case '<':
        temp[i] = '<';
        break;
      case '&':
        temp[i] = '&';
        break;
      case '>':
        temp[i] = '>';
        break;
      case '"':
        temp[i] = '"';
        break;
      case "'":
        temp[i] = "'";
        break;
    }
  }

  temp = temp.join('');
  return temp;
}

//test here
convertHTML("Dolce & Gabbana");
function convertHTML(str) {
//Chaining of replace method with different arguments
  str = str.replace(/&/g,'&').replace(/,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,"&apos;");
return str;
}

// test here
convertHTML("Dolce & Gabbana");
function convertHTML(str) {
      // Use Object Lookup to declare as many HTML entities as needed.
      htmlEntities={
        '&':'&',
        '<':'<',
        '>':'>',
        '"':'"',
        '\'':"'"
      };
      //Use map function to return a filtered str with all entities changed automatically.
      return str.split('').map(entity => htmlEntities[entity] || entity).join('');
    }

    // test here
    convertHTML("Dolce & Gabbana");

求斐波那契数组中的奇数之和

在这道题目中,我们需要写一个函数,参数为一个正整数num。它的作用是计算斐波那契数列中,小于或等于num的奇数之和。

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

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

function sumFibs(num) {
    var prevNumber = 0;
    var currNumber = 1;
    var result = 0;
    while (currNumber <= num) {
        if (currNumber % 2 !== 0) {
            result += currNumber;
        }

        currNumber += prevNumber;
        prevNumber = currNumber - prevNumber;
    }

    return result;
}

// test here
sumFibs(4);
function sumFibs(num) {
    // Perform checks for the validity of the input
    if (num < 0) return -1;
    if (num === 0 || num === 1) return 1;

    // Create an array of fib numbers till num
    const arrFib = [1, 1];
    let nextFib = 0;
    
    // We put the new Fibonacci numbers to the front so we
    // don't need to calculate the length of the array on each
    // iteration
    while((nextFib = arrFib[0] + arrFib[1]) <= num) {
        arrFib.unshift(nextFib);
    }

    // Sum only the odd numbers and return the value
    return arrFib.reduce((acc, curr) => {
        return acc + curr * (curr % 2);
    });
}

// test here
sumFibs(4);

对所有素数求和

在这道题目中,我们需要写一个函数,它接收一个数字参数num,返回值为不大于这个数字的所有质数之和。

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

注意,传入函数的num不一定是质数。

  • 在这道题目里我们也可以熟悉一下如何判断一个数是否为素数。
    判断一个数是否为素数有三种方法:
    1、遍历所有比该数小的数,看是否能被其他自然数整除。
    2、其实判断一个数是否为素质,不需要遍历所有数,只需要遍历小于等于该数的平方根的数。
function sumPrimes(num) {
  // function to check if the number presented is prime
  function isPrime(number){
      for (i = 2; i <= number; i++){
          if(number % i === 0 && number!= i){
          // return true if it is divisible by any number that is not itself.
             return false;
          }
       }
       // if it passes the for loops conditions it is a prime
      return true;
  }
  // 1 is not a prime, so return nothing, also stops the recursive calls.
  if (num === 1){
    return 0;
  }
  // Check if your number is not prime
  if(isPrime(num) === false){
  // for non primes check the next number down from your maximum number, do not add anything to your answer
    return sumPrimes(num - 1);
  }

  // Check if your number is prime
  if(isPrime(num) === true){
  // for primes add that number to the next number in the sequence through a recursive call to our sumPrimes function.
    return num + sumPrimes(num - 1);
  }
}
// test here
sumPrimes(10);
function sumPrimes(num) {
  // step 1	
  let arr = Array.from({length: num+1}, (v, k) => k).slice(2); 
  // step 2
  let onlyPrimes = arr.filter( (n) => { 
    let m = n-1;
    while (m > 1 && m >= Math.sqrt(n)) { 
      if ((n % m) === 0) 
        return false;
        m--;
    }
      return true;
  });
  // step 3
  return onlyPrimes.reduce((a,b) => a+b); 
}
// test here
sumPrimes(977);

还学会了一个小知识,就是利用

var arr = Array.from({length:100}, (v,k) => k);

不用循环创建一个0-99的数组。
此外还可以用[...Array(100).keys()]或者Array.from(new Array(100).keys())

最小公倍数

在这道题目中,我们需要写一个函数,它接收一个包含两个数字的数组参数arr,它的返回值为这两个数字范围内所有数字(包含这两个数字)的最小公倍数。

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

比如,传入[1, 3],那么函数的返回结果应为 1、2、3 的最小公倍数,即为 6。

function smallestCommons(arr) {
  let min = Math.min(arr[0],arr[1]);
  let max = Math.max(arr[0],arr[1]);
  let newArr = [];
  for(let i=max;i>=min;i--){
    newArr.push(i);
  }
  var quot = 0;
  var loop = 1;
  var n;
  do{
    quot = newArr[0]*loop*newArr[1];
    for(n=2;n<newArr.length;n++){
      if(quot % newArr[n] !== 0){
        break;
      }
    }
    loop++;
  }while(n!==newArr.length);
  return quot;
}


smallestCommons([1,5]);
function smallestCommons(arr) {
    var range = [];
    for (var i = Math.max(arr[0], arr[1]); i >= Math.min(arr[0], arr[1]); i--) {
    range.push(i);
    }

    // can use reduce() in place of this block
    var lcm = range[0];
    for (i = 1; i < range.length; i++) {
    var GCD = gcd(lcm, range[i]);
    lcm = (lcm * range[i]) / GCD;
    }
    return lcm;

    function gcd(x, y) {    // Implements the Euclidean Algorithm
    if (y === 0)
        return x;
    else
        return gcd(y, x%y);
    }
}

// test here
smallestCommons([1,5]);
function smallestCommons(arr) {

  // range
  let min = Math.min.apply(null, arr);
  let max = Math.max.apply(null, arr);

  let smallestCommon = lcm(min, min + 1);

  while(min < max) {
    min++;
    smallestCommon = lcm(smallestCommon, min);
  }

  return smallestCommon;
}

/**
 * Calculates Greatest Common Divisor
 * of two nubers using Euclidean algorithm
 * https://en.wikipedia.org/wiki/Euclidean_algorithm
 */
function gcd(a, b) {
  while (b > 0) {
    let tmp = a;
    a = b;
    b = tmp % b;
  }
  return a;
}

/**
 * Calculates Least Common Multiple
 * for two numbers utilising GCD
 */
function lcm(a, b) {
  return (a * b / gcd(a, b));
}


// test here
smallestCommons([1,5]);

补充小知识点:

欧几里得算法gcd算法寻找最大公因数

function gcd(x, y) {    // Implements the Euclidean Algorithm
    if (y === 0)
        return x;
    else
        return gcd(y, x%y);
    }

找出两个数的最小公倍数

function gcd(a, b) {
  while (b > 0) {
    let tmp = a;
    a = b;
    b = tmp % b;
  }
  return a;
}
function lcm(a, b) {
  return (a * b / gcd(a, b));
}

放弃

在这道题目中,我们需要写一个函数,它接收两个参数,分别为一个数组arr以及一个函数func。我们需要从数组的第一个元素开始,用func来检查数组的每项。函数最终的返回值也是一个数组,它由原数组中第一个使得func为true的元素及其之后的所有元素组成。

如果数组中的所有元素都不能让func为true,则返回空数组[]。

function dropElements(arr, func) {
  // drop them elements.
  var times = arr.length;
  for (var i = 0; i < times; i++) {
    if (func(arr[0])) {
      break;
    } else {
      arr.shift();
    }
  }
  return arr;
}

// test here
dropElements([1, 2, 3, 4], function(n) {return n >= 3;})
function dropElements(arr, func) {
  while(arr.length > 0 && !func(arr[0])) {
    arr.shift();
  }
  return arr;
}

// test here
dropElements([1, 2, 3, 4], function(n) {return n >= 3;});
function dropElements(arr, func) {
  return arr.slice(arr.findIndex(func) >= 0 ? arr.findIndex(func): arr.length, arr.length);
}

// test here
dropElements([1, 2, 3, 4], function(n) {return n >= 3;});

扁平化

在这道题目中,我们需要写一个数组扁平化的函数。

注意,你写的函数应该能够处理数组多级嵌套的情况。比如,[1, [2], [3, [4]]]在扁平化处理后的结果应为[1, 2, 3, 4]。

function steamrollArray(arr) {
  var flattenedArray = [];

  // Create function that adds an element if it is not an array.
  // If it is an array, then loops through it and uses recursion on that array.
  var flatten = function(arg) {
    if (!Array.isArray(arg)) {
      flattenedArray.push(arg);
    } else {
      for (var a in arg) {
        flatten(arg[a]);
      }
    }
  };

  // Call the function for each element in the array
  arr.forEach(flatten);
  return flattenedArray;
}

// test here
steamrollArray([1, [2], [3, [[4]]]]);
function steamrollArray(arr) {
  let flat = [].concat(...arr);
  return flat.some(Array.isArray) ? steamrollArray(flat) : flat;
}

flattenArray([1, [2], [3, [[4]]]]);
function steamrollArray(arr) {
  return arr.toString()
    .replace(',,', ',')       // "1,2,,3" => "1,2,3"
    .split(',')               // ['1','2','3']
    .map(function(v) {
      if (v == '[object Object]') { // bring back empty objects
        return {};
      } else if (isNaN(v)) {        // if not a number (string)
        return v;
      } else {
        return parseInt(v);         // if a number in a string, convert it
      }
    });
}

二进制转化

在这道题目中,我们需要写一个把二进制输入转换成英文句子的函数。

传入函数的二进制字符串会用空格作为分隔符。

function binaryAgent(str) {
      biString = str.split(' ');
      uniString = [];

    /*using the radix (or base) parameter in parseInt, we can convert the binary
      number to a decimal number while simultaneously converting to a char*/

      for(i=0;i < biString.length;i++){
        uniString.push(String.fromCharCode(parseInt(biString[i], 2)));
      }

      // we then simply join the string
      return uniString.join('');
    }

    // test here
    binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111");
 function binaryAgent(str) {
      return String.fromCharCode(...str.split(" ").map(function(char){ return parseInt(char, 2); }));
    }

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

真假值判断

在这道题目中,我们需要写一个函数,它接收两个参数。第一个参数为对象数组collection,第二个参数为一个字符串pre,代表对象的一个键(key)。我们需要检查对象数组中每个对象的pre属性对应的值是否都为 “真”(truthy)。如果是,则返回true,否则返回false。

JavaScript 中,如果一个值在 Boolean 的上下文中(比如if语句)可以被执行为true,那么这个值就被认为是truthy的。

注意,你可以选择使用.或[]来访问对象属性对应的值。

function truthCheck(collection, pre) {
  return collection.every(function (element) {
    return element.hasOwnProperty(pre) && Boolean(element[pre]);
  });
}

// test here
truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex");
function truthCheck(collection, pre) {
  // Is everyone being true?
  return collection.every(obj => obj[pre]);
}

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

可选参数

在这道题目中,我们需要写一个求和的函数,但它接收的参数数量不定。如果传入了两个参数,那么直接返回两数之和即可。如果只传入一个参数,那我们应该返回另一个函数用来接收下一个参数,然后求出两数之和。

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

然后我们调用这个返回的函数,并给它传入另一个用于求和的值:

var sumTwoAnd = addTogether(2);

sumTwoAnd(3)此时应返回5。

只要其中任何一个参数不是数字,那我们就应返回undefined。

 function addTogether() {
      // Function to check if a number is actually a number
      // and return undefined otherwise.
      var checkNum = function(num) {
        if (typeof num !== 'number') {
          return undefined;
        } else
          return num;
      };

      // Check if we have two parameters, check if they are numbers
      // handle the case where one is not
      // returns the addition.
      if (arguments.length > 1) {
        var a = checkNum(arguments[0]);
        var b = checkNum(arguments[1]);
        if (a === undefined || b === undefined) {
          return undefined;
        } else {
          return a + b;
        }
      } else {
        // If only one parameter was found, returns a new function that expects two
        // Store first argument before entering the new function scope
        var c = arguments[0];

        // Check the number again, must be outside the function to about returning an object
        // instead of undefined.
        if (checkNum(c)) {
          // Return function that expect a second argument.
          return function(arg2) {
            // Check for non-numbers
            if (c === undefined || checkNum(arg2) === undefined) {
              return undefined;
            } else {
              // if numbers then add them.
              return c + arg2;
            }
          };
        }
      }
    }

    // test here
    addTogether(2,3);
    function addTogether() {
      var args = new Array(arguments.length);
      //Storing the arguments in an array
      for(var i = 0; i < args.length; ++i) {
          args[i] = arguments[i];
        }
     //Check for the arguments length
     if(args.length == 2){
        //If there are two arguments,check for the type of both arguments
        //Use typeof to check the type of the argument(both should be numbers)
        if(typeof args[0] !== 'number' || typeof args[1] !=='number' ){
          return undefined;
          }
        return args[0]+args[1];
       }
     //When only one argument is provided
     if(args.length == 1){
         a= args[0];
         //Check the  argument using typeof 
        if(typeof a!=='number'){
            return undefined;
          }
        else{
           //Making use of closures 
           return function(b){
           //Checking the second argument 
             if(typeof b !=='number'){
               return undefined;
               }
             else
               return a+b;
              };
          }
        }
    }

    // test here
    addTogether(2,3);
    //jshint esversion: 6
    function addTogether() {
      var args = Array.from(arguments);
      return args.some(n => typeof n !== 'number') ? 
        undefined: 
        args.length > 1 ?
          args.reduce((acc, n) => acc += n, 0):
          (n) => typeof n === "number" ? 
            n + args[0]:
            undefined;
    }

    // test here
    addTogether(2,3);

构造一个 Person 类

在这道题目中,我们需要写一个构造器(constructor)函数。它只接收一个字符串参数firstAndLast,这个参数代表一个英文名的全名(姓和名)。这个构造函数创建出的实例需要具有以下方法:

getFirstName() getLastName() getFullName() setFirstName(first) setLastName(last) setFullName(firstAndLast)
这些方法应当可以通过构造函数创建出的实例调用。

var Person = function(firstAndLast) {
  var fullName = firstAndLast;

  this.getFirstName = function() {
    return fullName.split(" ")[0];
  };

  this.getLastName = function() {
    return fullName.split(" ")[1];
  };

  this.getFullName = function() {
    return fullName;
  };

  this.setFirstName = function(name) {
    fullName = name + " " + fullName.split(" ")[1];
  };

  this.setLastName = function(name) {
    fullName = fullName.split(" ")[0] + " " + name;
  };

  this.setFullName = function(name) {
    fullName = name;
  };
};

var bob = new Person('Bob Ross');
bob.getFullName();

绘制碎片图

在这道题目中,我们需要写一个计算天体轨道周期的函数,它接收一个对象数组参数arr,对象中包含表示天体名称的name属性,及表示轨道半长轴的avgAlt属性。就像这样:{name: ‘name’, avgAlt: avgAlt}。

这个函数的返回值也是一个对象数组,应保留原对象中的name属性和值,然后根据avgAlt属性的值求出轨道周期(单位是秒),并赋值给orbitalPeriod属性。返回值中不应保留原数据中的avgAlt属性及其对应的值。

function orbitalPeriod(arr) {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;
  var a = 2 * Math.PI;
  var newArr = [];
  var getOrbPeriod = function(obj) {
    var c = Math.pow(earthRadius + obj.avgAlt, 3);
    var b = Math.sqrt(c / GM);
    var orbPeriod = Math.round(a * b);
    delete obj.avgAlt;
    obj.orbitalPeriod = orbPeriod;
    return obj;
  };

  for (var elem in arr) {
    newArr.push(getOrbPeriod(arr[elem]));
  }

  return newArr;
}

// test here
orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
function orbitalPeriod(arr) {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;

  //Looping through each key in arr object
  for(var prop in arr) {
    //Rounding off the orbital period value
    var orbitalPer = Math.round(2 * Math.PI * Math.sqrt(Math.pow(arr[prop].avgAlt + earthRadius, 3) / GM));
    //deleting the avgAlt property
    delete arr[prop].avgAlt;
    //adding orbitalPeriod property
    arr[prop].orbitalPeriod = orbitalPer;
  }

  return arr;
}

// test here
orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
function orbitalPeriod(arr) {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;

  // Loop through each item in the array arr
  arr.forEach(function(item) {
    // Calculate the Orbital period value
    var tmp = Math.round(2 * Math.PI * Math.sqrt(Math.pow(earthRadius + item.avgAlt, 3) / GM));
    //Delete the avgAlt property
    delete item.avgAlt;
    //Add orbitalPeriod property
    item.orbitalPeriod = tmp;
  });
  return arr;
}

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

你可能感兴趣的:(JS数据结构)