核心提示:FCC的算法题一共16道。跟以前简单到使人发指的基础题目相比,难度是上了一个台阶。主要涉及初步的字符串,数组等运算。仍然属于基础的基础,官方网站给出的建议完成时间为50小时,超出了以前全部非项目题目的一倍还多。因而可知它的份量。现将本身的解题过程作个记录,有兴趣的人能够一块儿来试试。javascript
2017.1更新:java
博客门可罗雀,阅读数最高的几篇文章竟无一例外全是FCC的答案。聊天室里最多的话题是“我要源码”。拿来主义确实很好,但我但愿写本身的代码。若是有一两我的能贬低这些代码,提出更好的方案,那写这些笔记的目的就达到了。git
如今回看最初的代码,以为当初本身真是彻彻底底的初学者。如今呢?依然如旧。我但愿在追梦的路上,永远当一个初学者。正则表达式
在作项目的时候,这些问题实际上很常见。因此出于升级思惟,花一个小时重写大部分算法。原来的代码就不避丑了。算法
先把字符串转化成数组,再借助数组的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(''); }
若是用字母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);
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");
函数的返回值应该是一个数字。
这个没有用什么生疏的方法,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]; }思路会不会清晰点呢?
像'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; }
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]]);
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; } }
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; }
若是字符串的长度比指定的参数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; }
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);
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); }
举例,["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; }
在JavaScript中,假值有false
、null
、0
、""
、undefined
和 NaN
。
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])
思路:要逐步判断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);
举例: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; } } }
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中文聊天室热心的网友