Free Code Camp的JavaScript算法
翻转字符串(Reverse a String
)
实现:先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串。
function reverseString(str) {
newStr = str.split(""); //将字符串分割为单个字符,并且每个字符作均作为数组的一个元素
newStrReverse = newStr.reverse(); //翻转数组元素顺序
strUnordered = newStrReverse.join(""); //连接数组的每个元素,没有分隔符,组成一个字符串
return strUnordered;
}
reverseString("hello");
计算一个整数的阶乘(Factorialize a Number
)
使用n
表示一个整数,阶乘代表所有小于或等于n
的整数的乘积,阶乘写成n!
。
n! = 1 * 2 * 3 * ... * (n-1) * n
。
function factorialize(num) {
if(num <= 1) {
return 1; //处理num为0和1的情况,0!等于1。
} else {
return num * factorialize(num - 1); //递归调用factorialize()函数
}
}
factorialize(5);
字符串回文(Check for Palindromes
)
01、捣鼓了一下午,终于把回文数弄出来了。之前一直卡在怎么匹配出不带标点和空白的字符串上,finally还是找到了,就是个枚举的正则表达式...顺带看了点正则表达式的知识,明、后天好好看看正则表达式的内容。
02、就是找到了效率高一点的判断回文数的方法
- 如果一个字符串忽略标点符号、大小写和空格,顺着读和倒着读相同,则这个字符串是回文
palindrome
。 - 需要去掉字符串的标点符号和空格,并且将字符串全部转化为小写(或大写)来验证字符串是否回文。
function palindrome(str) {
//匹配所有标点符号(英文的),并且匹配所有空白符(/s)
var expression = /[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|<|\.|>|\/|\?|\s]+/g;
//使用replace()方法将所有标点和空白替换为空,相当于将所有文本字符连接在一起;并且将所有字符转化为小写(不会改变原字符串)
var allChar = str.replace(expression, "").toLowerCase();
//将字符串分割为单子字符数组,反转数组,再合并数组成一个字符串
var allLowerChar = allChar.split("").reverse().join(""); 、
//比较原字符串与反转后字符串是否相同,相同返回true,不同返回false
if(allLowerChar === allChar) {
return true;
} else {
return false;
}
}
palindrome("woca"); //调用
注:使用正则表达式expression = /[\~|\
|!|@|#|$|%|^|&|*|(|)|-|_|+|=|||\|[|]|{|}|;|:|"|'|,|<|.|>|/|?]+/g`可以匹配字符串中的所有标点符号。
去掉开头的\ |
,用于匹配空格,使用后面的\s
来匹配所有的空白符。
- 使用上述方法判断回文字符串,方便简单,但是效率不高,字符串的
split()
、reverse()
、join()
需要很多额外的操作。 - 回文字符串的特点:第一个字符和最后一个字符相同,第二个字符和倒数第二个字符相同...(回文字符串从左向右或是从右向左读都相同)
-
递归方法判断--推荐方法
递归的作用在于不断减小所处理问题的规模,直到可以解决为止。
回文字符串问题:可以每次比较端部的字符,如果相同则去掉,再次比较端部字符;如果不同则返回false
。直到只剩中间的字符、或不剩下字符时,返回true
。
function isPalindrome(str) {
var expression = /[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|<|\.|>|\/|\?|\s]*/g;
var allChar = str.replace(expression, "").toLowerCase();
for(var i = 0, j = allChar.length - 1; i < j; i++, j--) {
if(allChar.charAt(i) !== allChar.charAt(j)) {
return false;
} //.charAt(i)返回字符串索引为i位置的字符
}
return true; //如果执行完循环没有退出,`str`为回文字符串
}
isPalindrome("ooaaoo");
找到句子中最长的单词(Find the longest world in a string
)
- 找到提供的英文句子(字符串)中最长的单词,并计算它的长度;函数返回值是一个数组。
- 自己的思路:将整个字符串以空格分割,构建以每个单词为元素的数组(字符串的
.split( )
方法);在根据单词的长度排序整个数组,最长的字符串在数组的端部。
function findLongestWord(str) {
var strArray = str.split(" "); //转化为以单词为元素的数组,以空格为分隔符
var strSort = strArray.sort(function(a, b) {
return b.length - a.length; //递减排序(如果a-b则是递增排序),看看`sort(a, b)`的文档
});
var lenMax = strSort[0].length;
return lenMax;
}
findLongestWord("The quick brown fox jumped over the lazy dog");
- 可能存在的问题
1、没有去掉句子中的标点符号
2、当一个句子中有多个单词长度相同时如何处理
function titleCase(str) {
return str.toLowerCase().split(' ').map(function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
}).join(' '); //先将字符串全部转化为小写,再以空格分割为以单词为元素的数组,然后将每个单词的首字母大写,最后以空格连接每个元素,重新组合为字符串。
}
titleCase("I'm a little tea pot");
返回数组中的最大值(Return Largest Numbers in Arrays
)
- 数组的元素是数值数组,分别找到每个子数组的最大值,将其串联起来形成一个新的数组。
- 思路:写一个函数
largeOne(arr1)
,其功能是找到一个数组中的最大值,并将其返回;再写另一个函数,分别将每个数组作为参数传入largeOne
,最后将得到的值添加到一个新的数组中.push()
方法。
//返回一个数组中的最大值
function largeOne(arr) {
var max = 0;
for(var i = 0; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
return max;
}
//分别迭代每个数组,把最大值添加到新的数组中
function largestOfFour(arr) {
var newArr = [];
for(var i = 0; i < arr.length; i++) {
newArr.push(largeOne(arr[i])); //选出最大的值并添加到新的数组中
}
return newArr;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
检查一个字符串的结尾(Confirm the Ending
)
- 检查一个字符串
str
是否以指定的字符串target
结尾。 - 思路:利用
.slice()
方法,根据target
的长度,提取出str
的末尾部分,将之与target
比较,如果相同返回true
。
function confirmEnding(str, target) {
if(str.slice(str.length - target.length, str.length) === target) { //忽略slice()的第二个参数,默认提取到字符串的末尾
return true;
} else {
return false;
}
}
confirmEnding("Bastian", "n");
- 使用
.substr()
方法,类似于slice()
方法。
function confirmEnding(str, target) {
if(str.substr(str.length - target.length) === target) {
return true;
} else {
return false;
}
}
confirmEnding("Bastian", "n");
重复一个字符串(Repeat a String
)
- 重复一个字符串
num
次,如果num
为负,则返回一个空字符串。 - 思路:采用
+
操作符,可以连接+
左右两边的字符串,之间没有空格。使用一个for
循环实现叠加。
function repeat(str, num) {
var newStr = "";
if(num <= 0) {
return "";
} else {
for(var i = 0; i < num; i++) {
newStr += str;
}
}
return newStr;
}
repeat("abc", 3);
截断字符串(Truncate a String
)
- 问题描述:如果字符串长度大于指定的参数
num
,则将多余的部分用...
表示。(插入带字符串尾部的三个.
也会计入字符串长度,但是如果参数num <= 3
,则添加的三个.
不会计入字符串长度) - 思路:用一个
if
判断字符串长度是否大于num
,如果false
则返回原字符串;如果true
,在继续判断num
与3的关系,大于3时,.
计入字符串的长度;小于3时,.
不计入字符串长度。
function truncate(str, num) {
//如果字符串长度大于指定参数num
if(str.length > num) {
//如果参数num > 3
if(num > 3) {
return str.slice(0, num - 3) + "..."; //-3是三个.会计入字符串的长度
} else {
return str.slice(0, num) + "..."; //三个.不计入字符串长度
}
} else {
return str;
}
}
truncate("A-tisket a-tasket A green and yellow basket", 11);
将数组分割为若干块(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]];
。 - 思路:先分离
arr.length < size
和size <= 0
的情况,再利用.slice()
和.push()
操作,利用for
循环迭代提取arr
的数组块,并添加到新数组中。
function chunk(arr, size) {
var newStr = [];
var temp = [];
var len = arr.length;
if(len < size || size <= 0) {
return arr;
} else {
for(var i = 0; i < len; i += size) {
temp = arr.slice(i, i + size);
newStr.push(temp);
}
return newStr;
}
}
chunk(["a", "b", "c", "d"], 2);
注意:参考资料
Slasher Flick
- 返回一个数组被截断
n
个元素后还剩余的元素,截断从索引0
开始。 - 思路:直接采用数组的
.slice()
方法获取元素组的后n
个元素,赋值给新的空数组。
function slasher(arr, howMany) {
if(arr.length < howMany) {
return [];
} else {
var newArr = arr.slice(-(arr.length-howMany)); //采用负索引,访问数组的倒数元素
return newArr;
}
}
slasher([1, 2, 3], 2);
注:采用.splice()
方法,可以删除原数组中的前n
个元素。.splice()
会直接修改原数组。
function slasher(arr, howMany) {
if(arr.length < howMany) {
return [];
} else {
arr.splice(0, howMany); //参考MDNjs的文档
return arr;
}
}
slasher([1, 2, 3], 2);
Mutations
- 如果数组第一个字符串元素包含了第二个字符串元素的所有字符(忽略大小写),函数返回
true
,否则返回false
。 - 采用[
indexOf()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)方法,返回指定值在字符串对象中首次出现的位置。如果不存在,则返回
-1`。
function mutation(arr) {
var str1 = arr[0].toLowerCase();
var str2 = arr[1].toLowerCase();
var len = str2.length;
//遍历str2的每个字符,如果有一个字符不在str1中,则返回false,如果全部通过,则返回true
for(var i = 0; i < len; i++){
if(str1.indexOf(str2[i]) === -1) {
return false;
}
}
return true;
}
mutation(["hello", "hey"]);
Falsy Bouncer
- 删除数组中的所有假值(
false
、null
、0、undefined
、NaN
)。 - 思路:采用
.filter()
方法,过滤掉返回值为false
的数组元素,不会改变原数组。参考Boolean Object
function isFake(element) {
if(element) {
return true;
} else {
return false;
}
}
function bouncer(arr) {
var newArr = arr.filter(isFake);
return newArr; //filter()方法不会改变原数组
}
bouncer([7, "ate", "", false, 9]);
Seek and Destroy
- 实现一个摧毁
destroy()
函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。 - 思路:使用
arguments.length
获得传入的参数个数,去掉第一个,剩下的为需要摧毁的值。使用.includes()
方法作为过滤函数,判断第一个数组参数中的每个元素是否出现在后面的参数中,出现则过滤掉;其余分别.push()
到新的孔数组中。
function destroyer(arr) {
var tempArr = [];
var newArr = [];
var len = arguments.length;
//构建其余参数数组
for(var i = 1; i < len; i++) {
tempArr.push(arguments[i]); //使用arguments.length可以获得传入的参数数量
}
//遍历第一个数组参数,如果数组元素在tempArr中,则淘汰;如果不在,则增加到newArr中,最后得到淘汰后的数组
for(var j = 0; j < arguments[0].length; j++) {
if(!tempArr.includes(arguments[0][j])) {
newArr.push(arguments[0][j]);
}
}
return newArr; //使用arguments.length可以获得传入的参数个数
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
注:.filter()
方法没有想出怎么实现。。。
Where Do I Belong
- 先给数组排序,然后找到指定值在数组中的位置,最后返回位置的索引。
- 野路子:先将元素添加到数组后面,再对数组排序,然后遍历数组,找到插入的元素,最后循环变量
i
即是索引。
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; //返回第一个值得索引
}
}
}
where([5, 3, 20, 3], 5);
Caesars Cipher
-
Caesars Cipher
又称凯撒码(位移码),密码中的字母按照指定的位数来做位移,密码中的字母按照指定的数量来做位移。ROT13密码:字母向后移动13个位置,A->N
,B->O
,N->A
...,ROT13(ROT13(x)) == x
。 - 思路:先将字符串
.split("")
方法,将字符串中的每个字符分给为一个数组元素,然后遍历数组元素。如果Unicode码在[97, 122]之间(只有大写字母),则按照算法向后推算;如果不在,则保持原状(空格和标点不处理)。 - 方法:当Unicode码在[65-77]之间时,直接每个加上13然后重新赋值;在[78-90]之间时,每个加上13,再减去26,最后赋值。
function rot13(str) { // LBH QVQ VG!
var newArr = str.split("");
var arr = [];
//大写字母的Unicode码从65到90
//如果在78-90之间,Unicode值减去13,;在65-77之间,Unicode值加上13
//最后转化为字符。
for(var i = 0; i < newArr.length; i++) {
if(newArr[i].charCodeAt() <= 90 && newArr[i].charCodeAt() >= 78) {
arr[i] = String.fromCharCode(newArr[i].charCodeAt() - 13);
} else if(newArr[i].charCodeAt() <= 77 && newArr[i].charCodeAt() >= 65) {
arr[i] = String.fromCharCode(newArr[i].charCodeAt() + 13);
} else {
arr[i] = newArr[i]; //不在65-90之间的不处理,略去空格和标点
}
}
return arr.join(""); //组合回字符串
}
// Change the inputs below to test
rot13("SERR PBQR PNZC");
居然做完了
哈哈,花了也不知道几天的空余时间,终于刷完了这点儿题,其中大部分都是自己完成,有些参考了网上的代码,不过都是亲手敲出来的码,哈哈哈哈,自己居然能想出来!