1. 程式人生 > 其它 >freeCodeCamp (JavaScript中級演算法題)學習

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 。

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;
這世上所有美好的東西,都需要踮起腳尖。