基础javascript算法

终于把FCC的基础javascript算法做完了,来总结一下。

翻转字符串

先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串。

1
2
3
4
5
6
7
8
function reverseString(str) {
var arr = str.split("");
var arrs = arr.reverse();
var rts = arr.join("");
return rts;
}
reverseString("hello");

主要用到了

  1. str.split()分割字符串并生成数组。
  2. arr.reverse()反转数组,把第一个转到最后一个,最后一个转到第一个。
  3. arr.join()在数组中每两个元素中加入一个字符串组成新的字符串arr.join("")就是什么都不加入。

计算一个整数的阶乘

这个之前写过了,在这里

检测给定的字符是否是回文

这个之前也写过了,在这里

找到提供的句子中最长的单词,并计算它的长度

1
2
3
4
5
6
7
8
9
10
11
12
function change(a,b) {
if(a.length > b.length) return -1;
return 1;
}
function findLongestWord(str) {
var arr = str.split(" ");
var newArr = arr.sort(change);
//return newArr.length;
return newArr[0].length;
}
findLongestWord("The quick brown fox jumped over the lazy dog");

主要用到了sort排序,详细在这里

确保字符串的每个单词首字母都大写,其余部分小写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function titleCase(str) {
var newStr = str.toLowerCase();
var arr = newStr.split(" ");
for (var i = 0; i < arr.length; i++) {
var char = arr[i].charAt(0);
arr[i] = arr[i].replace(char,function rep(char) {
return char.toUpperCase();
});
}
var xstr = arr.join(" ");
return xstr;
}
titleCase("sHoRt AnD sToUt");

用到了str.toLowerCase()str.replace()str.toUpperCase()

思路大概是:字符串换成小写,转换成数组。遍历数组找到每个字符串的首字母(用str.charAt())。然后用str.replace()把首字母替换为大写。在把数组转换为字符串输出。

str.replace()方法:stringObject.replace(regexp/substr,replacement);regexp/substr为需要替换的对象,replacement为替换后的对象,可以为一个函数,比如文中用到的:

1
2
3
arr[i] = arr[i].replace(char,function rep(char) {
return char.toUpperCase();
});

返回数组中最大的数

右边大数组中包含了4个小数组,分别找到每个小数组中的最大值,然后把它们串联起来,形成一个新数组。
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])应该返回[5,27,39,1001]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function change(a,b){
if (a>b) return -1;
return 1;
}
function largestOfFour(arr) {
// You can do this!
var maxx = [];
var maxNum = [];
for(var i = 0; i < arr.length; i++) {
maxx[i] = arr[i].sort(change);
maxNum[i] = maxx[i][0];
}
return maxNum;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

依然用到sort排序。

思路:遍历数组,sort对数组排序,并传到新数组中对应的位置maxx[i] = arr[i].sort(change);然后找到各个数组中最大的数传到另一个数组中maxNum[i] = maxx[i][0];

检查一个字符串(str)是否以指定的字符串(target)结尾

1
2
3
4
5
6
7
8
function confirmEnding(str, target) {
var targetL = target.length;
var newStr = str.substring(str.length-targetL,str.length);
if (newStr == target) return true;
return false;
}
confirmEnding("He has to give me a new", "name");

思路:截取字符串最后几位,检查是否等于给定的target

重要的事情说3遍!

重复一个指定的字符串 num次,如果num是一个负数则返回一个空字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
function repeat(str, num) {
// repeat after me
var newStr = str.split(" ");
if (num < 0) return "";
else {
for (var i = 0; i < num; i++) {
newStr[i] = str;
}
return newStr.join("");
}
}
repeat("abc", 3);

思路:这个其实不难,就是不好想出来,新建一个数组,然后在i<num的时候开始循环,新数组的[i]对应给定的str,这样num是多少,就循环了多少遍,新数组中就有多少个元素。

截断一个字符串!

如果字符串的长度比指定的参数num长,则把多余的部分用…来表示。

切记,插入到字符串尾部的三个点号也会计入字符串的长度。

但是,如果指定的参数num小于或等于3,则添加的三个点号不会计入字符串的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function truncate(str, num) {
// Clear out that junk in your trunk
var strSub;
if (str.length > num) {
if(num > 3) {
strSub = str.substring(0,num-3);
return strSub+"...";
} else {
strSub = str.substring(0,num);
return strSub+"...";
}
}
return str;
}
truncate("A-tisket a-tasket A green and yellow basket", 11);

主要用到了str.substring(start,end),从start处开始截取,到end处截止。
难点在与如果指定的参数num小于或等于3,则添加的三个点号不会计入字符串的长度。
这个要写if..else来判断

把一个数组按照指定的数组大小分割成若干个数组块。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function chunk(arr, size) {
// Break it up.
var num1 = Math.floor(arr.length / size);
var num2 = arr.length % size;
var arr2 = [];
if (num2 === 0) {
for (var i = 0; i < num1; i++) {
arr2[i] = arr.slice(i * size,size * (i + 1));
//return arr2;
}
}else {
for (var j = 0; j <= num1; j++) {
arr2[j] = arr.slice(j * size,size * (j + 1));
//return arr2;
}
}
return arr2;
}
chunk([0, 1, 2, 3, 4, 5], 4);

用到arr.slice()来切割数组。

思路主要是:

  1. 先计算出分成几大段并赋值给num1,再计算出分段后剩余的(用求余计算)并赋值给num2;新建一个数组arr2。
  2. 开始判断,如果余数为0,也就是正好分段完没有剩余字符。此时进行遍历并储存切割后的字符

    1
    2
    3
    for (var i = 0; i < num1; i++) {
    arr2[i] = arr.slice(i * size,size * (i + 1));
    }
  3. 如果余数不为0,进行另一种赋值

    1
    2
    3
    for (var j = 0; j <= num1; j++) {
    arr2[j] = arr.slice(j * size,size * (j + 1));
    }

难点还是在于遍历的同时完成切割后字符的储存,之前一直想直接返回数组,结果只会返回第一个值。后来想了一个方法:新建一个数组,遍历的同时进行新数组第i个赋值,完美。

返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始。

slasher([1, 2, 3], 2)应该返回 [3].
slasher([“burgers”, “fries”, “shake”], 1)应该返回 [“fries”, “shake”].

1
2
3
4
5
6
function slasher(arr, howMany) {
// it doesn't always pay to be first
return arr.slice(howMany,arr.length);
}
slasher([1, 2, 3], 2);

这个如果想到了还挺简单的,用arr.clice(),输入两个参数,一个起始位置,一个结束位置,就可以输出了。

如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true。

mutation([“Mary”, “Army”])应该返回 true.
mutation([“hello”, “neo”])应该返回 false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function mutation(arr) {
var rarr = [];
var str1 = arr[0].toLowerCase();
var str2 = arr[1].toLowerCase();
for (var i = 0; i < str2.length; i++) {
rarr[i] = str1.indexOf(str2[i]);
}
var rstr = rarr.join("");
if (rstr.indexOf("-1") >= 0) {
return false;
} return true;
}
mutation(["Mary", "Army"]);

思路:用str.indexOf()找到第二个字符串各个字符在第一个字符串中的位置(找不到为-1)并储存为一个新数组;然后对储存位置的数组进行判断,找到数组中-1(也就是不被字符串1包含的字符)的位置,如果>=0,就意味着位置数组中确实存在值为-1的元素,也就是第二个字符串中有不被第一个字符串包含的字符。返回false.反之如果值为-1的元素在位置数组中的位置为-1,就证明不存在,也就是字符串2中的字符全能在字符串1中找到,此时返回true。

删除数组中的所有假值。

在JavaScript中,假值有falsenull0""undefinedNaN

1
2
3
4
5
6
7
8
9
function bouncer(arr) {
// Don't show a false ID to this bouncer.
function change(arr) {
return !(arr === null || arr === false || arr === undefined || arr === 0 || arr === "" || arr !== arr);
}
return arr.filter(change);
}
bouncer([false, null, 0, NaN, undefined, ""]);

关于null,undefined,NaN的区别之前写过,点这里跳转

主要用到了arr.filter(callback),用来返回满足callback函数的值。

实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。

destroyer([1, 2, 3, 1, 2, 3], 2, 3)应该返回 [1, 1].

destroyer([“tree”, “hamburger”, 53], “tree”, 53)应该返回 [“hamburger”].

1
2
3
4
5
6
7
8
9
10
11
12
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);

用到arguments.object:arguments 是一个类数组对象。代表传给一个function的参数列表。你可以传递任意数量的参数到该函数,然后该函数会将每个参数作为一个条目来创建一个列表。

比如destroyer(arr)这个函数,只有一个参数,那么如何处理destroyer([1, 2, 3, 1, 2, 3], 2, 3);呢?
没错,[1, 2, 3, 1, 2, 3], 2, 3全部都是arguments这个类数组。可以理解为arguments=[[1, 2, 3, 1, 2, 3], 2, 3]

但是arguments对象并不是一个真正的Array 。它类似于数组,但没有数组所特有的属性和方法,除了 length。例如,它没有 pop 方法。

思路:新建一个储存被删除值的数组arrDel,开始对arguments进行遍历,注意val i = 1;因为不需要对第一个(也就是arr)进行遍历。

然后把arguments各个元素push进arrDel.然后

1
2
return arr.filter(function(val) {
return arrDel.indexOf(val)<0;});

先给数组排序,然后找到指定的值在数组的位置,最后返回位置对应的索引。

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。

1
2
3
4
5
6
7
8
9
10
11
function where(arr, num) {
// Find my place in this sorted array.
var newArr = arr.concat(num);
function change(a,b) {
if (b - a >0) return -1;
return 1;
}
return newArr.sort(change).indexOf(num);
}
where([2, 20, 10], 19);

思路:用arr.concat拼接数组,然后利用sort排序,然后用indexOf返回索引值就可以了。

写一个ROT13函数,实现输入加密字符串,输出解密字符串。

下面我们来介绍风靡全球的凯撒密码Caesar cipher
,又叫移位密码。

移位密码也就是密码中的字母会按照指定的数量来做移位。

一个常见的案例就是ROT13密码,字母会移位13个位置。由’A’ ↔ ‘N’, ‘B’ ↔ ‘O’,以此类推。

写一个ROT13函数,实现输入加密字符串,输出解密字符串。

所有的字母都是大写,不要转化任何非字母形式的字符(例如:空格,标点符号),遇到这些特殊字符,跳过它们。

rot13(“SERR PBQR PNZC”)应该解码为 “FREE CODE CAMP”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function rot13(str) {
var newArr=[];
for(var i=0;i<str.length;i++){
if(str.charCodeAt(i)<65||str.charCodeAt(i)>90){
newArr.push(str.charAt(i));
}else if(str.charCodeAt(i)>77){
newArr.push(String.fromCharCode(str.charCodeAt(i)-13));
}else{
newArr.push(String.fromCharCode(str.charCodeAt(i)+13));
}
}
return newArr.join("");
}
// Change the inputs below to test
rot13("SERR PBQR PNZC");

这个主要考察unicode编码。

charCodeAt()方法返回0到65535之间的整数,代表索引处字符的UTF-16编码单元(在Unicode编码单元表示一个单一的UTF-16编码单元的情况下,UTF-16编码单元匹配Unicode编码单元。否则,比如Unicode 编码单元 > 0x10000 的情况下,只能匹配Unicode代理对的第一个编码单元)。如果你希望得到整点编码值,使用codePointAt()

思路:

  1. 26个字母的unicode码在65(A)与90(Z)之间,第13位M(77);
  2. 将str通过.charCodeAt()转为unicode编码并放入新数组;
  3. 其中非字母形式的字符直接放入.charAt();
  4. 后13位字母减去13后放入;
  5. 前13位字母加上13后放入;
  6. 通过.fromCharCode()转化为字母,将数组转化为字符串;

基础javascript算法就到这了,很多算法虽然写出来了,但是应该不是最优解,但是现在我还想不出来更好的解法。先这样吧,如有错误,欢迎指正。

努力<br><br>希望能成为一名前端工程师<br>加油