FreeCodeCamp - Basic Algorithm Scripting
这一部分真的要做笔记了,要不然又会忘掉。
Reverse a String
翻转字符串
先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串。
你的结果必须得是一个字符串
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function reverseString(str) {
str = str.split("").reverse().join("");
return str;
}
reverseString("hello");
str.split()
是将对象分割成字符串数组。
reverse()
颠倒数组串中的元素位置,第一个元素会成为最后一个,最后一个会成为第一个。
join()
将数组的元素链接到一个字符串中。
括号中的 ""
是分割数组,例如:
function myFunction(){
var str="How are you doing today?";
var n=str.split("");
return n;
}
输出:H,o,w, ,a,r,e, ,y,o,u, ,d,o,i,n,g, ,t,o,d,a,y,?
Factorialize a Number
计算一个整数的阶乘
如果用字母n来代表一个整数,阶乘代表着所有小于或等于n的整数的乘积。
阶乘通常简写成 n!
例如: 5! = 1 * 2 * 3 * 4 * 5 = 120
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function factorialize(num) {
if (num<2) {
return 1;
}
for(var i=1,result=1;i<=num;i++) {
result = result*i;
}
return result;
}
factorialize(5);
//i<=0是循环0次啊大哥,所以factorialize(0)时直接就是 i=1,recult=1了
这题要这样想,0! 和 1! 都是1,所以要搞一个 if
函数来设定 num
小于 0 时结果为 1。
关于 for 循环,通常是先赋予 i
一个值,让 i
小于或大于一个值或者长度,用 i++
i--
来循环。
Check for Palindromes
如果给定的字符串是回文,返回true
,反之,返回false
。
如果一个字符串忽略标点符号、大小写和空格,正着读和反着读一模一样,那么这个字符串就是palindrome(回文)。
注意你需要去掉字符串多余的标点符号和空格,然后把字符串转化成小写来验证此字符串是否为回文。
函数参数的值可以为"racecar"
,"RaceCar"
和"race CAR"
。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function palindrome(str) {
// Good luck!
var arr = str.toLowerCase().replace(/[^a-z0-9]/g,"");
var reversearr = arr.split("").reverse().join("");
if (arr == reversearr) {
return true;
} else {
return false;
}
}
palindrome("eye");
网上大神有详尽的正则表达式的解释
关于正则
在给出答案之前,先简单说说这道题的正则如何写最好
在这道题目中,我们需要把空格、特殊符号都去掉。
.replace()
方法接收的第一个参数为一个正则表达式(或字符),第二个参数为字符(或一个 function)。作用就是把通过第一个参数匹配到的字符给替换成第二个参数的字符。括号中的参数类型,这道题中并不会用到那么,我们需要做的就是,在第一个参数中匹配空格和特殊符号,第二个参数中传入
""
空字符,顺便,记得要在正则结尾写上/g
,否则不能替换全部匹配空格和特殊符号,空格是
\s
(请注意,反之不成立,\s
不光是空格,还包括制表符 tab,以及换行符\r
或者\r\n
)。然而,特殊符号,并没有一个通用的匹配写法有些朋友可能会想这样做,事实上我也真的见过有不少人这样做:
/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/g
,嗯,没毛病但我们换一种思路想想,其实我们要做的,就是"保留英文字母和数字"。这样,正则就变得简单很多了,只需要
/[^A-Za-z0-9]/g
。另一方面,如果你先.toLowerCase()
再.replace()
,正则就可以直接写成/[^a-z0-9]/g
如果你决定用
\w
的相反形式\W
,没有问题,但一定要记住,\w
不仅包含英文字母,还包含了下划线_
。因此,你需要写成/[\W_]/g
,或者写成/\W|_/g
toLowerCase()
会将调用该方法的字符串值转为小写形式,并返回。
replace()
方法返回一个由替换值替换一些或所有匹配的模式后的新字符串。模式可以是一个字符串或者一个 正则表达式 , 替换值可以是一个字符串或者一个每次匹配都要调用的函数。
这里的难点估计就是正则表达式了,我们来看这段代码:
var arr = str.toLowerCase().replace(/[^a-z0-9]/g,"");
/[^a-z0-9]
代表的意思是除了 26 个字母和所有数字。
/g
代表全局匹配,如果不加,则只会匹配第一个元素。
.replace(/[^a-z0-9]/g,"");
所以这句话的意思是,把除了 26 个字母和所有数字的其他元素全部换成 ""
。
Find the Longest Word in a String
找到提供的句子中最长的单词,并计算它的长度。
函数的返回值应该是一个数字。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function findLongestWord(str) {
var strArr = str.split(" ");
var max = strArr[0].length;
for (i=0;i<strArr.length;i++) {
if (strArr[i].length>=max) {
max = strArr[i].length;
}
}
return max;
}
findLongestWord("The quick brown fox jumped over the lazy dog");
先使这段语句成为数组,用 str.split(" ")
。
赋予 max
为 strArr[0].length
,即数组第一个单词的长度。
用 for
函数历遍数组中的所有元素
如果元素(即 strArr[i].length
)的长度比 max
大,就会更新 max
函数。
Title Case a Sentence
确保字符串的每个单词首字母都大写,其余部分小写。
像'the'和'of'这样的连接符同理。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
其实这一题不光有 String.split() 还不够,还要有:
我的解法:
function titleCase(str) {
var strArr = str.toLowerCase().split(" ");
for (i=0;i<strArr.length;i++) {
strArr[i]=strArr[i][0].toUpperCase()+strArr[i].slice(1);
}
return strArr.join(" ");
}
titleCase("I'm a little tea pot");
这里主要是 slice()
不太懂,这是代表提取字符串的一部分,并返回一新的字符串。
slice(1)
就是代表提取字符串从 2 开始的到最后一个字符。
substr()
是返回一个字符串中从指定位置开始到指定字符数的字符。
slice()
和 substr()
可以互换。
Return Largest Numbers in Arrays
右边大数组中包含了4个小数组,分别找到每个小数组中的最大值,然后把它们串联起来,形成一个新数组。
提示:你可以用for循环来迭代数组,并通过arr[i]
的方式来访问数组的每个元素。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function largestOfFour(arr) {
// You can do this!
var maxArr = [];
for (var i=0;i<arr.length;i++) {
var max = arr[i][0];
for (var j=0;j<arr[i].length;j++) {
if (arr[i][j]>=max) {
max=arr[i][j];
}
}
maxArr[i]=max;
}
return maxArr;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
这道题是这样的,先设置一个空的数组 maxArr
用 for
函数历遍 arr
。赋予 max
为每个 arr[i]
元素里面的第一个元素
再用 for
函数历遍 arr[i]
,如果 arr[i][j]>=max
,刷新 max
。
max
返回 maxArr[i]
得出数组
Confirm the Ending
检查一个字符串(str
)是否以指定的字符串(target
)结尾。
如果是,返回true;如果不是,返回false。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function confirmEnding(str, target) {
// "Never give up and good luck will find you."
// -- Falcor
var last = str.substr(str.length-target.length);
if (last == target){
return true;
}
return false;
}
confirmEnding("Bastian", "n");
例题中 str.length-target.length
得出来的是 5 ,即从 6 个字符开始算,last
得到 n
。
Repeat a string repeat a string
重要的事情说3遍!
重复一个指定的字符串 num
次,如果num
是一个负数则返回一个空字符串。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function repeat(str, num) {
// repeat after me
var arr = "";
for (i=0;i<num;i++) {
arr += str;
}
return arr;
}
repeat("abc", 3);
估计我对 for
函数没有那么熟悉吧,这道题搞得我一蒙一蒙的。。
arr += str;
是指 arr = arr + str ,num
有多大,这条式子就循环多少次。
Truncate a string
用瑞兹来截断对面的退路!
截断一个字符串!
如果字符串的长度比指定的参数num
长,则把多余的部分用...
来表示。
切记,插入到字符串尾部的三个点号也会计入字符串的长度。
但是,如果指定的参数num
小于或等于3,则添加的三个点号不会计入字符串的长度。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function truncate(str, num) {
// Clear out that junk in your trunk
if (str.length<=num) {
return str;
} else {
if (num<=3) {
return str.slice(0,num)+"...";
} else {
return str.slice(0,num-3)+"...";
}
}
}
truncate("A-tisket a-tasket A green and yellow basket", 11);
这里主要运用了 str.slice()
的函数
如果语句的长度小于等于 num
则直接返回 str
如果不是,这里要分两种情况,一种是比 num
大于等于 3 。一种是 num
小于 3的情况
因为 truncate(str, num)
的 num
是包括小数点的,小数点占 3 位,而题目要求的是如果指定的参数num
小于或等于3,则添加的三个点号不会计入字符串的长度
所以条件 if
设为 if (num<=3) { return str.slice(0,num)+"...";}
这样的话,假如是 truncate(abcd, 2)
。会返回 "ab..."
Chunky Monkey
猴子吃香蕉可是掰成好几段来吃哦!
把一个数组arr
按照指定的数组大小size
分割成若干个数组块。
例如:chunk([1,2,3,4],2)=[[1,2],[3,4]];
chunk([1,2,3,4,5],2)=[[1,2],[3,4],[5]];
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function chunk(arr, size) {
// Break it up.
var result=[];
for (var i=0;i<arr.length;i+=size) {
var temp=[];
for (var j=i;j<i+size;j++) {
if (j<arr.length) {
temp.push(arr[j]);
}
}
result.push(temp);
}
return result;
}
chunk(["a", "b", "c", "d"], 2);
我自己是这样理解的,假如 size
是 2,arr
是[1,2,3]
那第一个 for
循环到 4 就会推出
设一个临时数组 temp
所以 temp
会有两 []
因为循环两次退出
i+=size
会加到 2 就停止,所以就只会到 2
所以会 temp.push(arr[2])
就是 [1,2]
剩下不是还有一个 3 么,它会作为一个余数加到 temp
里
所以返回数组 [[1,2],[3]]
真的要找个时间补补循环了
网上大神这样解释
解释
- 整体思路应该不难理解。外层的
i
用于确定截取的起始点。内层的j
就是在i
与i + size
之间,读出每一个元素,并存储到temp
中。每存好一个片段 (即内层循环结束),就把temp
保存到result
中- 这个思路的关键在于选对
i
和j
的初始值以及循环过程中增值。既然我们需要实现每size
个元素为一个片段,那么我们肯定需要确定每次截取的起点和终点- 我们用
i
来表示截取的起点,那么不难得出i
的初始值为 0。增值应该为size
。跳出条件也很简单,只要i < arr.length
,我们就可以一直执行- 用
j
来选取范围中的元素,因此j
的初始值应该就为i
(注意,这个i
是会变化的)。至于j
的结束值,那么应该为i + size
。因为我们需要截取的是从i
到i + size
的元素。j
的增值显然应该为j++
,因为我们需要获取这个范围之内的所有元素- 既然我们设置了
j
是从i
到i + size
,那么就需要处理i + size
超出数组长度的情况。简单考虑下这个例子,传入数组[1, 2, 3, 4, 5]
,size
为4
,那么我们应该得到[[1, 2, 3, 4], [5]]
。当i
为 0 的时候没有问题,但当第二次循环,即i
为 4 的时候,这时j
也为 4。而内层循环跳出条件,i + size
为 8,显然超出了原数组的长度。如果我们读取arr[6]
,会得到undefined
,显然我们不想把这个结果放进temp
- 那么如何判断呢?你可能第一反应是用
if (arr[j])
来判断。可以先试试,结果是通不过测试的。原因在于 JavaScript 的隐式类型转换,if()
中的内容会被转换成Boolean
,相当于执行的是if(Boolean(arr[j]))
或者说if(!!arr[j])
。那么如果arr[j]
是 0,就也会返回 false。但其实,0
在数组中肯定是允许的情况,我们不应该把它排除掉- 因此,这里我们只需要简单地判断
j
是否超出了arr.length
即可。也就有了上面的代码
Slasher Flick
打不死的小强!
返回一个数组被截断n
个元素后还剩余的元素,截断从索引0开始。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function slasher(arr, howMany) {
// it doesn't always pay to be first
arr.splice(0,howMany);
return arr;
}
slasher([1, 2, 3], 2);
这题挺简单的,arr.splice(0,howMany)
就是删掉 0 到 howMany 的元素。
Mutations
蛤蟆可以吃队友,也可以吃对手。
如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true。
举例,["hello", "Hello"]
应该返回true,因为在忽略大小写的情况下,第二个字符串的所有字符都可以在第一个字符串找到。
["hello", "hey"]
应该返回false,因为字符串"hello"并不包含字符"y"。
["Alien", "line"]
应该返回true,因为"line"中所有字符都可以在"Alien"找到。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
function mutation(arr) {
var a=arr[0].toLowerCase();
var b=arr[1].toLowerCase();
for (var i=0;i<b.length;i++) {
if (a.indexOf(b[i])<0) {
return false;
}
}
return true;
}
mutation(["hello", "hey"]);
这一道题要这样想先设置 arr
的第一个元素为 a ,第二的元素为 b 。并用 toLowerCase()
变成小写。
把数组 b
的一个一个元素和数组 a
匹配,如果没有匹配到该值,返回 -1,返回 false
,反则返回 turn
。
还是要多看 str.indexOf();
Falsy Bouncer
真假美猴王!
删除数组中的所有假值。
在JavaScript中,假值有false
、null
、0
、""
、undefined
和 NaN
。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function bouncer(arr) {
// Don't show a false ID to this bouncer.
var result=[];
for (var i=0;i<arr.length;i++) {
if (Boolean(arr[i])) {
result.push(arr[i]);
}
}
return result;
}
bouncer([7, "ate", "", false, 9]);
把 result
设为一个空的数组
for
循环每个元素
boolean
不为假值就会加到数组 result
得出一个没有假值的数组。
Seek and Destroy
金克斯的迫击炮!
实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
我的解法:
function destroyer(arr) {
// Remove all the values
var arrDel=[];
for (var i=1;i<arguments.length;i++) {
arrDel.push(arguments[i]);
}
return arr.filter(function(val) {
return arrDel.indexOf(val)<0;
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
这题是我觉得最难的一题了,刚开始一点头绪都没有,一步一步分析
var arrDel=[];
先建立一个空数组
for (var i=1;
这个是跳过代删元素 [1, 2, 3, 1, 2, 3]
i<arguments.length;i++
创建一个类似列表的东西 [[1, 2, 3, 1, 2, 3], 2, 3]
,因为跳过了代删元素,所以只会在 2,3
循环
把 2,3
加到 arrDel
数组中
返回到 arr.filter(function(val)
进行删除值,而且要通过 arrDel.indexOf(val)<0;
的验证,比如:
function(2) {
return arrDel.indexOf(2)<0;
}
arrDel.indexOf(2)
这一段是返回 4 的,所以成立
经过验证,2,3
是要删除的数字,删掉后返回 [1,1]
Where do I belong
我身在何处?
先给数组排序,然后找到指定的值在数组的位置,最后返回位置对应的索引。
举例: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
。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
function where(arr, num) {
// Find my place in this sorted array.
arr.push(num);
arr.sort(function(a,b){
return a - b;
});
return arr.indexOf(num);
}
where([40, 60], 50);
先把num
加到数组
用 arr.sort()
把数组里的元素从小到大排列
用 arr.indexOf()
获得元素的索引值
function(a,b){
return a - b;
}
JavaScript 高级程序设计P94
由于比较函数通过返回一个小于零、等于零或大于零的值来影响排序结果,因此减法操作就可以适当的处理这些情况。
Caesars Cipher
让上帝的归上帝,凯撒的归凯撒。
下面我们来介绍风靡全球的凯撒密码Caesar cipher
,又叫移位密码。
移位密码也就是密码中的字母会按照指定的数量来做移位。
一个常见的案例就是ROT13密码,字母会移位13个位置。由'A' ↔ 'N', 'B' ↔ 'O',以此类推。
写一个ROT13函数,实现输入加密字符串,输出解密字符串。
所有的字母都是大写,不要转化任何非字母形式的字符(例如:空格,标点符号),遇到这些特殊字符,跳过它们。
当你完成不了挑战的时候,记得开大招'Read-Search-Ask'。
这是一些对你有帮助的资源:
function rot13(str) { // LBH QVQ VG!
var result="";
for (var i=0;i<str.length;i++) {
var currentCode=str[i].charCodeAt();
if (currentCode>90||currentCode<65) {
result += String.fromCharCode(currentCode);
} else if (currentCode < 78) {
result += String.fromCharCode(currentCode + 13);
} else {
result += String.fromCharCode(currentCode - 13);
}
}
return result;
}
// Change the inputs below to test
rot13("SERR PBQR PNZC");
这里要先知道什么是 ASCII 码,A 到 M 的 ASCII 码是 65 到 77,N 到 Z 的 ASCII 码是 78 到 90
String.prototype.charCodeAt()
方法返回0到65535之间的整数,表示给定索引处的UTF-16代码单元 (在 Unicode 编码单元表示一个单一的 UTF-16 编码单元的情况下,UTF-16 编码单元匹配 Unicode 编码单元。但在——例如 Unicode 编码单元 > 0x10000 的这种——不能被一个 UTF-16 编码单元单独表示的情况下,只能匹配 Unicode 代理对的第一个编码单元) 。如果你想要整个代码点的值,使用 codePointAt()。
举个栗子:
下例返回 65,即 A 的 Unicode 值:
"ABC".charCodeAt(0) // returns 65
String.fromCharCode()
静态 String.fromCharCode() 方法返回使用指定的Unicode值序列创建的字符串。
举个栗子:
下例返回字符串 "ABC":
String.fromCharCode(65,66,67)
只要理解了这些其实这些算法也没有想象中那么难,不过我觉得还是要打好基础才行,不说了,先去看一遍 JavaScript 高级程序设计吧。
(完)