FCC上的初級算法題

核心提示:FCC的算法題一共16道。跟以前簡單到使人髮指的基礎題目相比,難度是上了一個臺階。主要涉及初步的字符串,數組等運算。仍然屬於基礎的基礎,官方網站給出的建議完成時間爲50小時,超出了以前全部非項目題目的一倍還多。因而可知它的份量。現將本身的解題過程作個記錄,有興趣的人能夠一塊兒來試試。javascript

2017.1更新:java

博客門可羅雀,閱讀數最高的幾篇文章竟無一例外全是FCC的答案。聊天室裏最多的話題是「我要源碼」。拿來主義確實很好,但我但願寫本身的代碼。若是有一兩我的能貶低這些代碼,提出更好的方案,那寫這些筆記的目的就達到了。git

如今回看最初的代碼,以爲當初本身真是徹徹底底的初學者。如今呢?依然如舊。我但願在追夢的路上,永遠當一個初學者。正則表達式

在作項目的時候,這些問題實際上很常見。因此出於升級思惟,花一個小時重寫大部分算法。原來的代碼就不避醜了。算法


1.翻轉字符串

先把字符串轉化成數組,再借助數組的reverse方法翻轉數組順序,最後把數組轉化成字符串。
你的結果必須得是一個字符串數組

function reverseString(str) {
  return str;
}

reverseString("hello");

思路:
(1)字符串轉數組用的是split方法,數組轉字符串用join方法app

split()方法經過把字符串分割成子字符串來把一個 String 對象分割成一個字符串數組。參數函數

固然,你也能夠作一個循環把字符串一個個加回去優化

(2) 倒序重排數組用的是reverse方法網站

解法
var newStr='';
function reverseString(str) {
  var arr=str.split('');//把字符串分割爲['h','e','l','l','o']
  arr.reverse();//倒序排列數組
  newStr=arr.join('');//把數組轉爲字符串
  return newStr;//別忘了返回。
}
reverseString("hello");

2017.1更新:

function reverseString(str) {
  return str.split('').reverse().join('');
}

2.計算一個整數的階乘

若是用字母n來表明一個整數,階乘表明着全部小於或等於n的整數的乘積。
階乘一般簡寫成 n!
例如: 5! = 1 * 2 * 3 * 4 * 5 = 120

function factorialize(num) { 
  return num;
}

factorialize(5);

思路:用循環,*=作、所須要注意的只是循環起點。

function factorialize(num) {
  var i=1;
  var product=1;

  for(i=1;i<=num;i++){
    product*=i;
  }
  return product;
}

factorialize(5);

3.若是給定的字符串是迴文,返回true,反之,返回false

若是一個字符串忽略標點符號、大小寫和空格,正着讀和反着讀如出一轍,那麼這個字符串就是palindrome(迴文)。

注意你須要去掉字符串多餘的標點符號和空格,而後把字符串轉化成小寫來驗證此字符串是否爲迴文。

函數參數的值能夠爲"racecar""RaceCar""race CAR"

function palindrome(str) {
  // Good luck!
  return true;
}

palindrome("eye");

思路,要轉化字符串爲無標點的字符串須要兩個方法
(1)replace() 方法
用於在字符串中用一些字符替換另外一些字符,或替換一個與正則表達式匹配的子串。xxx。replace(正則表達式,'xxxx')
(2)轉換小寫——toLowerCase()

2017.1 追加:其實這是比較有價值的題目。

function palindrome(str) {
  // Good luck!
  var newStr= str.replace(/\W+/g,'');//匹配全部非單詞的字符,替換爲空字符串
  newStr= newStr.replace(/\_+/g,'');//匹配全部下劃線,替換爲空字符串 
  newStr=newStr.toLowerCase();
  //轉化字符串爲小寫
  var arr1= newStr.split('');

  var arr2=arr1.reverse();
  var newStr2=arr2.join('');
  //重構倒序的字符串
  if(newStr===newStr2){//比較1
    return true;
  }else{
   return false;
  }
}

一個優化的思路:

function palindrome(str) {
  // Good luck!
  str = str.replace(/[^A-Za-z0-9]/g,'').toLowerCase();
  for(var i=0;i<str.length/2;i++){
    if(str[i]!==str[str.length-i-1]){
      return false;
    }
  }
  return true;
}

還有更簡單的思路

function palindrome(str) {
  // Good luck!
  var re = /[\W\s_]/gi;
  str = str.replace(re,"");
  return str.toLowerCase() === str.split("").reverse().join("").toLowerCase();
}

palindrome("eye");

4.找到提供的句子中最長的單詞,並計算它的長度。

函數的返回值應該是一個數字。
這個沒有用什麼生疏的方法,split拆分字符串,而後循環判斷最長的String.length;

function findLongestWord(str) {
  var arr=str.split(' ');
  var wordLength=0;
  for(i=0;i<arr.length;i++){
    if(arr[i].length>wordLength){
      wordLength=arr[i].length;
      LongestWord=arr[i];
    }
  }
  return wordLength;
}

findLongestWord("The quick brown fox jumped over the lazy dog");

2017.1追加:

function findLongestWord(str) {
    var arr=str.split(' ');
    arr=arr.map(function(item){
        return item.length;
    }).sort(function(a,b){
        return b-a;
    });

  return arr[0];
}

思路會不會清晰點呢?

5.確保字符串的每一個單詞首字母都大寫,其他部分小寫。

像'the'和'of'這樣的鏈接符同理。
思路,先用split拆分單詞,在拆分單詞的每一個字母,首個字母設置大寫,後面的所有設置小寫。而後再組合成詞,最後再組合爲句子。

function titleCase(str) {
  var arr=str.split(' ');
  for(i=0;i<arr.length;i++){
    arr2=arr[i].split('');
    arr2[0]=arr2[0].toUpperCase();
    for(j=1;j<arr2.length;j++){
      arr2[j]=arr2[j].toLowerCase();
    }
    
    arr[i]=arr2.join('');

  }
  var newStr=arr.join(' ');
  
  return newStr;
}

2017.1追加:

思路是在map遍歷中構造一個新的詞組。

function titleCase(str) {
    
    var newStr=str.toLowerCase().split(' ').map(function(item){
        return item[0].toString().toUpperCase()+item.slice(1);
    }).join(' ');

    return newStr;
}

6.右邊大數組中包含了4個小數組,分別找到每一個小數組中的最大值,而後把它們串聯起來,造成一個新數組。

function largestOfFour(arr) {
  // You can do this!
  return arr;
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

提示:你能夠用for循環來迭代數組,並經過arr[i]的方式來訪問數組的每一個元素。
思路,主要是用了數組排序的方法。

function largestOfFour(arr) {
  // You can do this!
  var newArr=[];
  for(i=0;i<arr.length;i++){
    arr[i].sort(function(a,b){
      return b-a;
    });
    
    newArr.push(arr[i][0]);
  }
    return newArr;

}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

7.檢查一個字符串(str)是否以指定的字符串(target)結尾。

若是是,返回true;若是不是,返回false。
思路:主要是用到了substr() 方法
substr() 方法可在字符串中抽取從 start 下標開始的指定數目的字符。

var str="Hello world!"
document.write(`str.substr(3)`)

輸出結果:

lo world!

根據這個方法,能夠用String.length來截取想要的部分進行判斷。

function confirmEnding(str, target) {
  if(str.substr(str.length-target.length)==target){
    return true;
  }else{
    return false;
  }
}

2017.1更新:

題目提示用substr方法,可是slice或許更好閱讀一些

function confirmEnding(str, target) {

  if(str.slice(-target.length)==target){
    return true;
  }else{
    return false;
  }
}

8.重複一個指定的字符串 num次,若是num是一個負數則返回一個空字符串。

沒什麼可說的

function repeat(str, num) {
  // repeat after me
  var str0=str;
  if(num<=0){
    return '';
  }else{
    for(i=0;i<num-1;i++){
      str+=str0;
    }
    return str;
  }
}

2017.1更新:

function repeat(str, num) {
  // repeat after me
  var newStr='';
  for(var i=1;i<=num;i++){
      newStr+=str;  
  }
  return newStr;
}

9.截斷一個字符串!

若是字符串的長度比指定的參數num長,則把多餘的部分用...來表示。
切記,插入到字符串尾部的三個點號也會計入字符串的長度。
可是,若是指定的參數num小於或等於3,則添加的三個點號不會計入字符串的長度。

function truncate(str, num) {
  // Clear out that junk in your trunk
  return str;
}

truncate("A-tisket a-tasket A green and yellow basket", 11);

思路:
slice() 方法可提取字符串的某個部分,並以新的字符串返回被提取的部分。好比說:

var str="Hello happy world!"
document.write(str.slice(6,17))//輸出"happy world"
function truncate(str, num) {
  // Clear out that junk in your trunk
  var newStr='';
  if(str.length>num){
    if(num<=3){
      newStr=str.slice(0,num)+'...';
    }else{
      newStr=str.slice(0,num-3)+'...';
    }
    return newStr;
  }else{
    return str;
  }
}

2017.1更新:

function truncate(str, num) {
  var result='';
  if(str.length<=num){
    result=str;
  }else{
    result=num>3?str.slice(0,num-3)+'...':str.slice(0,num)+'...';
  }
  return result;
}

10.把一個數組arr按照指定的數組大小size分割成若干個數組塊。

例如:chunk([1,2,3,4],2)=[[1,2],[3,4]];
chunk([1,2,3,4,5],2)=[[1,2],[3,4],[5]];

function chunk(arr, size) {
  // Break it up.
  return arr;
}

chunk(["a", "b", "c", "d"], 2);

若是不用slice作,要對狀況作分類討論:

function chunk(arr, size) {
  // Break it up.
  var newArr=[];
  var i=0;
  var tempArr=[];
  if(arr.length%size!==0){
    for(i=0;i<=arr.length;i++){
      if(tempArr.length==size){
          newArr.push(tempArr);
          tempArr=[];
        }
      if(i==arr.length){
        newArr.push(tempArr);
        break;
      }

      tempArr.push(arr[i]);
    }

  }else{
    for(i=0;i<=arr.length;i++){
        if(tempArr.length==size){
          newArr.push(tempArr);
          tempArr=[];
        }
        tempArr.push(arr[i]);
    }
  }

而slice方法能夠這樣實現:

function chunk(arr ,size) {
  var newarr=[];
  for(var i=0;i<arr.length;i+=size) {
    newarr.push(arr.slice(i,i+size));
  }
  return newarr;
}

chunk(["a", "b", "c", "d"], 2);

11.返回一個數組被截斷n個元素後還剩餘的元素,截斷從索引0開始。

function slasher(arr, howMany) {
  // it doesn't always pay to be first
  if(howMany===0){
    return arr;
  }
  arr=arr.splice(howMany,arr.length-1);
  return arr;
  
}

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

2017.1更新:

貌似這樣就能夠了

function slasher(arr, howMany) {
  // it doesn't always pay to be first
  return arr.slice(howMany);
}

12.若是數組第一個字符串元素包含了第二個字符串元素的全部字符,函數返回true。

舉例,["hello", "Hello"]應該返回true,由於在忽略大小寫的狀況下,第二個字符串的全部字符均可以在第一個字符串找到。

["hello", "hey"]應該返回false,由於字符串"hello"並不包含字符"y"。

["Alien", "line"]應該返回true,由於"line"中全部字符均可以在"Alien"找到。

var str="Hello world!"
document.write(str.indexOf("Hello") + "
")//0
document.write(str.indexOf("World") + "
")//-1

最直接的辦法

function mutation(arr) {

  var a1=arr[0].toLowerCase();

  var a2=arr[1].toLowerCase();

  if(a1===a2){

    return true;

  }else{

    var count=0;
    for(i=0;i<a2.length;i++){
      for(j=0;j<a1.length;j++){
        if(a2[i]==a1[j]){
          count+=1;
        }
      }
    }
    if(count>=a2.length){
      return true;
    }else{
      return false;
    }

  }
}

2017.1更新:

如今看來真心不叫直接

function mutation(arr) {
  arr[0]=arr[0].toLowerCase();
  arr[1]=arr[1].toLowerCase();

  for(var i=0;i<arr[1].length;i++){
        if(arr[0].indexOf(arr[1][i])==-1){
            return false;
        }
    }
  return true;
}

13.刪除數組中的全部假值。

在JavaScript中,假值有falsenull0""undefinedNaN

function bouncer(arr) {
  // Don't show a false ID to this bouncer.
  arr=arr.filter(function(a){
    return a
  });
  return arr;
}
bouncer([7, "ate", "", false, 9])

14.實現一個摧毀(destroyer)函數,第一個參數是待摧毀的數組,其他的參數是待摧毀的值。

思路:要逐步判斷arr內的每一個參數值,知足同樣的刪除掉便可,可是在循環內刪除會破壞結構,因此能夠先替換爲一個false,而後再來用filter判斷返回出真值。

function destroyer(arr) {
  // Remove all the values
  for(i=1;i<arguments.length;i++){
    for(j=0;j<arr.length;j++){
      if(arr[j]==arguments[i]){
        arr.splice(j,1,"false");//起始項數,要刪除的值數,添加項內容
        // 原來的代碼是 arr.splice(j,1,false);通過網友提示應該改成別的flag量
      }
    }

  }
  arr=arr.filter(function(a){
    return a!=="false";
  });
  return arr;
}

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

2017.1更新

這貌似是聊天室裏要源碼最多的問題之一。因而我看到了這種解法

Array.prototype.slice.call(arguments)能將具備length屬性的對象轉成數組.

function destroyer(arr) {
  // Remove all the values
  var mainArr = arguments[0],
      filtArr = Array.prototype.slice.call(arguments, 1);

  return mainArr.filter(function(value,index){
    return filtArr.indexOf(value) === -1;
  });

}

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

15.先給數組排序,而後找到指定的值在數組的位置,最後返回位置對應的索引。

舉例:where([1,2,3,4], 1.5) 應該返回 1。由於1.5插入到數組[1,2,3,4]後變成[1,1.5,2,3,4],而1.5對應的索引值就是1

同理,where([20,3,5], 19) 應該返回 2。由於數組會先排序爲 [3,5,20]19插入到數組[3,5,20]後變成[3,5,19,20],而19對應的索引值就是2

思路:用一個索引值index來標記num本應在數組的位置。在遍歷比較以後插入數組。

function where(arr, num) {
  // Find my place in this sorted array.
  arr.sort(function(a,b){
    return a-b;
  });

 
  var index=0;
  for(i=0;i<arr.length;i++){
    if(arr[i]<num){
      index+=1;
    }
    
  }
  arr.splice(index,0,num);
   console.log(arr);
  return index;
}

where([40, 60], 50);

2017.1更新

function where(arr, num) {
  // Find my place in this sorted array.
  arr.push(num);
  arr.sort(function(a,b){
    return a-b;
  });
  for(var i=0;i<arr.length;i++){
    if(arr[i]==num){
        return i;
    }
  }
}

16.下面咱們來介紹風靡全球的凱撒密碼Caesar cipher,又叫移位密碼。

移位密碼也就是密碼中的字母會按照指定的數量來作移位。

一個常見的案例就是ROT13密碼,字母會移位13個位置。由'A' ↔ 'N', 'B' ↔ 'O',以此類推。

寫一個ROT13函數,實現輸入加密字符串,輸出解密字符串。

全部的字母都是大寫,不要轉化任何非字母形式的字符(例如:空格,標點符號),遇到這些特殊字符,跳過它們。
思路:
(1)每一個字符都有本身的鍵碼,相關的編碼能夠在鍵碼錶查到。根據需求:大寫字母A-Z的鍵碼爲60-90。只要獲取每一個字符串的鍵碼(String.charCodeAt()方法),回退13位,就能夠得到解密後的鍵碼。最後把它輸出爲相應的字母(String.fromCharCode()方法)。
(2)首先要判斷的是:鍵碼60-90閉區間外的字符不予編譯。
(3)其次,明文的鍵碼解密以後可能退到不屬於大寫字母的編碼區,好比加密明文爲A的時,直接回退再編譯就變成了數字3,所以須要給它在此基礎上加上大寫字母表的個數26。再進行判斷。這實現了整個編譯區相對於明文區的偏移。

function rot13(str){ // LBH QVQ VG!
  var newStr='';
  for(i=0;i<str.length;i++){
    if(str[i].charCodeAt(0)>90||str[i].charCodeAt(0)<65){
      newStr+=str[i];
    }else{
      var newStrCode=str[i].charCodeAt(0)-13;
      if(newStrCode<65){
        newStrCode+=26;
      }
      newStr+=String.fromCharCode(newStrCode);
    }
  }
  return (newStr);

}
// Change the inputs below to test
rot13("LBH QVQ VG");

題目來源:

FCC中文網:https://www.freecodecamp.cn/

參考資料:

[1]《javascript高級程設計》第4,5,6章。
[2] MOZILLA開發者社區:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
[3]W3school: http://www.w3school.com.cn/ [4]感謝gitter中文聊天室熱心的網友

相關文章
相關標籤/搜索