目录
JavaScript脚本算法编程实战课程
1、区间求值算法挑战
2、找出数组间差异算法挑战
3、数字转罗马数字
4、对象搜索算法挑战
5、字符串查询替换算法挑战
6、字符串移动插入算法挑战
7、字符配对算法挑战
8、字符串查询补充算法挑战
9、输入检查算法挑战
10、数组去重算法挑战
11、html符号转实体算法挑战
12、字符串连接算法挑战
13、斐波纳契奇数求和算法挑战
14、质素求和算法挑战
15、最小公倍数算法挑战
16、数组验证算法挑战
17、数组取值算法挑战
18、数组平铺算法挑战
18、二进制转字符算法挑战
19、数组元素判断算法挑战
20、函数迭代可选参数算法挑战
我们会传递给你一个包含两个数字的数组。返回这两个数字和它们之间所有数字的和。
最小的数字并非总在最前面。
function sumAll(arr) { var sum = 0; for (var i = Math.min(arr[0],arr[1]); i <= Math.max(arr[0],arr[1]); i++) { sum += i; } return sum; } sumAll([1, 4]);
运行结果:10
比较两个数组,然后返回一个新数组,该数组的元素为两个给定数组中所有独有的数组元素。换言之,返回两个数组的差异。
function diff(arr1, arr2) { var newArr = []; // Same, same; but different. for (var i = 0; i < arr1.length; i++) { var flag1 = true; for (var j = 0; j < arr2.length; j++) { if (arr1[i] == arr2[j]) { flag1 = false; break; } } if(flag1){ newArr = newArr.concat(arr1.slice(i,i+1)); } } for (var m = 0; m < arr2.length; m++) { var flag2 = true; for (var n = 0; n < arr1.length; n++) { if (arr2[m] == arr1[n]) { flag2 = false; break; } } if(flag2){ newArr = newArr.concat(arr2.slice(m,m+1)); } } return newArr; } diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);
运行结果:[4]
将给定的数字转换成罗马数字。
所有返回的 罗马数字 都应该是大写形式。
function convert(num) { var romanNum = []; switch (num % 10 / 1) { case 1: romanNum.splice(0,0,"I"); break; case 2: romanNum.splice(0,0,"II"); break; case 3: romanNum.splice(0,0,"III"); break; case 4: romanNum.splice(0,0,"IV"); break; case 5: romanNum.splice(0,0,"V"); break; case 6: romanNum.splice(0,0,"VI"); break; case 7: romanNum.splice(0,0,"VII"); break; case 8: romanNum.splice(0,0,"VIII"); break; case 9: romanNum.splice(0,0,"IX"); break; } switch (Math.floor(num % 100 / 10)) { case 1: romanNum.splice(0,0,"X"); break; case 2: romanNum.splice(0,0,"XX"); break; case 3: romanNum.splice(0,0,"XXX"); break; case 4: romanNum.splice(0,0,"XL"); break; case 5: romanNum.splice(0,0,"L"); break; case 6: romanNum.splice(0,0,"LX"); break; case 7: romanNum.splice(0,0,"LXX"); break; case 8: romanNum.splice(0,0,"LXXX"); break; case 9: romanNum.splice(0,0,"XC"); break; } switch (Math.floor(num % 1000 / 100)) { case 1: romanNum.splice(0,0,"C"); break; case 2: romanNum.splice(0,0,"CC"); break; case 3: romanNum.splice(0,0,"CCC"); break; case 4: romanNum.splice(0,0,"CD"); break; case 5: romanNum.splice(0,0,"D"); break; case 6: romanNum.splice(0,0,"DC"); break; case 7: romanNum.splice(0,0,"DCC"); break; case 8: romanNum.splice(0,0,"DCCC"); break; case 9: romanNum.splice(0,0,"CM"); break; } switch (Math.floor(num % 10000 / 1000)) { case 1: romanNum.splice(0,0,"M"); break; case 2: romanNum.splice(0,0,"MM"); break; case 3: romanNum.splice(0,0,"MMM"); break; /* case 4: romanNum.splice(0,0,"MV"); break; case 5: romanNum.splice(0,0,"D"); break; case 6: romanNum.splice(0,0,"DC"); break; case 7: romanNum.splice(0,0,"DCC"); break; case 8: romanNum.splice(0,0,"DCCC"); break; case 9: romanNum.splice(0,0,"CM"); break;*/ } return romanNum.join(""); } convert(12);
运行结果:XII
此方法用到过多的switch语句,不建议过多使用switch,此题只是提供一种思维方式,推荐读者寻找新的方法。
写一个 function方法,它遍历一个对象数组(第一个参数)并返回一个包含相匹配的属性-值对(第二个参数)的所有对象的数组。如果返回的数组中包含 source 对象的属性-值对,那么此对象的每一个属性-值对都必须存在于 collection 的对象中。
例如,如果第一个参数是 [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }],第二个参数是 { last: "Capulet" },那么你必须从数组(第一个参数)返回其中的第三个对象,因为它包含了作为第二个参数传递的属性-值对。
function where(collection, source) { var arr = []; // What's in a name? var sourceKeys = []; var key; for(key in source){ sourceKeys.push(key); } for (var i = 0; i < collection.length; i++) { var collectionKeys =[]; for(key in collection[i]){ collectionKeys.push(key); } var flag = true; for(key in sourceKeys){ if (collectionKeys.join("").indexOf(sourceKeys[key]) == -1 || source[sourceKeys[key]] != collection[i][sourceKeys[key]]) { flag = false; break; } } if(flag){ arr.push(collection[i]); } } return arr; } where([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
运行结果:[{"first":"Tybalt","last":"Capulet"}]
使用给定的参数对字符串执行一次查找和替换,然后返回新字符串。
第一个参数是将要对其执行查找和替换的字符串。
第二个参数是将被替换掉的单词(替换前的单词)。
第三个参数用于替换第二个参数(替换后的单词)。注意:替换时保持原单词的大小写。例如,如果你想用单词 "dog" 替换单词 "Book" ,你应该替换成 "Dog"。
运行结果:A quick brown fox leaped over the lazy dogfunction myReplace(str, before, after) { var strArr = str.split(before); var afterArr = after.split(""); var codeNum = afterArr[0].charCodeAt(); if (before.charCodeAt(0) >= 65 && before.charCodeAt(0) <= 90 && codeNum >= 97 && codeNum <= 122) { afterArr[0] = String.fromCharCode(codeNum - 32); } else if (before.charCodeAt(0) >= 97 && before.charCodeAt(0) <= 122 && codeNum >= 65 && codeNum <= 90){ afterArr[0] = String.fromCharCode(codeNum + 32); } after = afterArr.join(""); str = strArr.join(after); return str; } myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
把指定的字符串翻译成 pig latin。
Pig Latin 把一个英文单词的第一个辅音或辅音丛(consonant cluster)移到词尾,然后加上后缀 "ay"。
如果单词以元音开始,你只需要在词尾添加 "way" 就可以了。输入字符串保证是英文单词全部小写。
function translate(str) { var strArr = str.split(""); var expression = /[aeiou]/; var index; for (var i = 0; i < strArr.length; i++) { if(strArr[i].match(expression)){ index = i; break; } } if(index === 0){ strArr.push("way"); }else{ for (var j = 0; j < index; j++) { strArr.push(strArr.shift()); } strArr.push("ay"); } str = strArr.join(""); return str; } translate("consonant");
运行结果:onsonantcay
DNA 链缺少配对的碱基。依据每一个碱基,为其找到配对的碱基,然后将结果作为第二个数组返回。
Base pairs(碱基对) 是一对 AT 和 CG,为给定的字母匹配缺失的碱基。
在每一个数组中将给定的字母作为第一个碱基返回。
例如,对于输入的 GCG,相应地返回 [["G", "C"], ["C","G"],["G", "C"]]字母和与之配对的字母在一个数组内,然后所有数组再被组织起来封装进一个数组。
function pair(str) { var strArr = str.split(""); var parentArr = []; for (var i = 0; i < str.length; i++) { var childArr = []; childArr.push(str.slice(i,i+1)); switch (str.slice(i,i+1)) { case 'G': childArr.push("C"); break; case 'C': childArr.push("G"); break; case 'T': childArr.push("A"); break; case 'A': childArr.push("T"); break; default: break; } parentArr.push(childArr); } return parentArr; } pair("GCG");
运行结果:[["G","C"],["C","G"],["G","C"]]
从传递进来的字母序列中找到缺失的字母并返回它。
如果所有字母都在序列中,返回 undefined。
function fearNotLetter(str) { var _return; for (var i = 0; i < str.length - 1; i++) { if (str[i+1].charCodeAt() - str[i].charCodeAt() > 1) { _return = String.fromCharCode(str[i].charCodeAt() + 1); break; }else{ _return = undefined; } } return _return; } fearNotLetter("abcdefghjklmno");
运行结果:i
检查一个值是否是基本布尔类型,并返回 true 或 false。
基本布尔类型即 true 和 false。
function boo(bool) { // What is the new fad diet for ghost developers? The Boolean. var flag = false; if(typeof bool == "boolean"){ flag = true; } return flag; } boo(null);
运行结果:false
写一个 function,传入两个或两个以上的数组,返回一个以给定的原始数组排序的不包含重复值的新数组。
换句话说,所有数组中的所有值都应该以原始顺序被包含在内,但是在最终的数组中不包含重复值。非重复的数字应该以它们原始的顺序排序,但最终的数组不应该以数字顺序排序
function unite(arr1, arr2, arr3) { var arg = arguments; for (var i = 0; i < arguments[0].length - 1; i++) { for (var j = i + 1; j < arguments[0].length; j++) { if(arguments[0][i] == arguments[0][j]){ arguments[0].splice(i,1); } } } for (var k = 1; k < arguments.length; k++) { for (var l = 0; l < arguments[k].length; l++) { if(arguments[0].indexOf(arguments[k][l]) == -1){ arguments[0].push(arguments[k][l]); } } } return arguments[0]; } unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
运行结果:[1,3,2,5,4]
将字符串中的字符 &、<、>、" (双引号), 以及 ' (单引号)转换为它们对应的 HTML 实体。
function convert(str) { // :) var strArr = str.split(""); var newArr = {}; for(var i in strArr){ var ele = /[\&\<|\>|\]|\"|\']/.exec(str[i]); // console.log(ele); if (ele !== null) { switch (ele[0]) { case '\&': ele[0] = "&"; break; case '\<': ele[0] = "<"; break; case '\>': ele[0] = ">"; break; case '\"': ele[0] = """; break; case '\'': ele[0] = "'"; break; default: // code } newArr[i] = ele[0]; } } for(var j in newArr){ strArr.splice(j,1,newArr[j]) } return strArr.join(""); } convert("Dolce & Gabbana");
运行结果:Dolce & Gabbana
将字符串转换为 spinal case。Spinal case 是 all-lowercase-words-joined-by-dashes 这种形式的,也就是以连字符连接所有小写单词。
function spinalCase(str) { // "It's such a fine line between stupid, and clever." // --David St. Hubbins var strArr = str.split(/[\ |_]/g); if(strArr.length == 1){ strArr = str.replace(str[0],str[0].toLowerCase()).replace(/([A-Z])/g,"-$1").split(/[\ |_]/g); } console.log(strArr); return strArr.join("-").toLowerCase(); } spinalCase('This Is Spinal Tap');
运行结果:this-is-spinal-tap
给一个正整数num,返回小于或等于num的斐波纳契奇数之和。
斐波纳契序列中的前两个数字是1和1.序列中的每个附加数字是前面两个数字的和。斐波纳契序列的前六个数字是1,1,2,3,5和8。
例如,sumFibs(4)应该返回 5,因为斐波纳契数列中所有小于4的奇数是 1、1、3。
提示:此题不能用递归来实现斐波纳契数列。因为当num较大时,内存会溢出,推荐用数组来实现。
function sumFibs(num) { var a1 = 1, a2 = 1; var arr = []; var sum = 0; if (num === 0) { arr.push(0); } else if (num == 1) { arr.push(a1); } else if (num > 1){ arr.push(a1); while(sum <= num) { arr.push(a2); sum = a2 + a1; a1 = a2; a2 = sum; } } num = 0; for(var i in arr){ if(arr[i] % 2 !== 0){ num += Number(arr[i]); } } return num; } sumFibs(4);
运行结果:5
求小于等于给定数值的质数之和。
只有 1 和它本身两个约数的数叫质数。例如,2 是质数,因为它只能被 1 和 2 整除。1 不是质数,因为它只能被自身整除。给定的数不一定是质数。
function sumPrimes(num) { var sum = 0; var arr = []; var i; for (i = 2; i <= num; i++){ var flag = true; if(i != 2 && i!= 3){ for (var k = 2; k <= Math.sqrt(i); k++) { if(i % k === 0){ flag = false; break; } } } if(flag){ arr.push(i); } } for(var j in arr){ sum += arr[j]; } return sum; } sumPrimes(10);
运行结果:17
找到所提供参数的最小公倍数,这两个参数可以均匀分配,以及这些参数之间范围内的所有最小公倍数。
范围是两个数字构成的数组,两个数字不一定按数字顺序排序。例如对 1 和 3 —— 找出能被 1 和 3 和它们之间所有数字整除的最小公倍数。
function smallestCommons(arr) { var num = Math.min(arr[0],arr[1]); for (var i = num; i <= Math.max(arr[0],arr[1]); i++) { num = minimumCommonMultiple(num,i); } console.log(num); return num; } //穷举法求两个数的最大公约数 function greatestCommonDivisor1(a,b){ var num = null; if(Math.min(a,b) !== 0){ for (var i = Math.min(a,b); i > 0; i--) { if(a % i === 0 && b % i ===0){ num = i; break; } } }else{ num = 0; } return num; } //相减法求两个数的最大公约数 function greatestCommonDivisor2(a,b){ var maxNum = Math.max(a,b); var minNum = Math.min(a,b); if(minNum === 0){ return 0; } while(maxNum - minNum !== 0){ if(maxNum > minNum){ maxNum = maxNum - minNum; }else{ minNum = minNum - maxNum; } } return maxNum; } //辗转求余法求两个数的最大公约数 function greatestCommonDivisor3(a,b){ var maxNum = Math.max(a,b); var minNum = Math.min(a,b); var num; if(minNum===0){ num = 0; } if(minNum !== 0){ while(minNum !==0){ num = maxNum % minNum; maxNum = minNum; minNum = num; } num = maxNum; } return num; } //两个数的最小公倍数 function minimumCommonMultiple(a,b){ var num; if(a === 0 || b === 0){ num = 0; }else{ num = a * b / greatestCommonDivisor1(a,b); } return num; } smallestCommons([1,5]);
运行结果:60
此题运用的是目标转换的思维方式:两个数的最小公倍数=这两个数的乘积 / 这两个数的最大公约数,所以先求出两个数的最大公约数,转而再求最小公倍数。
写一个 function,它查找数组(第一个参数)并返回数组中第一个通过某种方法(第二个参数)验证的元素。
function find(arr, func) { var num = 0; for(var i in arr){ if (func(arr[i])) { num = arr[i]; break; } num = undefined; } return num; } find([1, 2, 3, 4], function(num){ return num % 2 === 0; });
运行结果:2
删除数组(第一个参数)的元素,从左边开始,直到回调函数(第二个参数)return true就停止。
第二个参数,func,是一个函数。用来测试数组的第一个元素,如果返回fasle,就从数组中抛出该元素(注意:此时数组已被改变),继续测试数组的第一个元素,如果返回fasle,继续抛出,直到返回true。最后返回数组的剩余部分,如果没有剩余,就返回一个空数组。
function drop(arr, func) { // Drop them elements. var newArr = []; for(var i in arr){ if (func(arr[i])) { newArr = arr.slice(i); break; } } return newArr; } drop([1, 2, 3], function(n) {return n < 3; });
运行结果:[1,2,3]
对嵌套的数组进行平铺嵌套数组。你必须考虑到不同层级的嵌套。
运行结果:["a","b"]var newArr = []; function steamroller(arr) { // I'm a steamroller, baby for(var i in arr){ if (!Array.isArray(arr[i])) { newArr.push(arr[i]); } else { steamroller(arr[i]); } } return newArr; } steamroller([[["a"]], [["b"]]]);
这种方法返回结果是正确的,但是在W3Cschool通不过测试,我就很郁闷了。
function steamroller(arr) { // I'm a steamroller, baby var newArr = []; for (var i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { newArr.push.apply(newArr, steamroller(arr[i])); } else { newArr.push(arr[i]); } } return newArr; } steamroller([[["a"]], [["b"]]]);
第二种方法结果也是没问题,能通过测试。这种方法中用到Function.prototype.apply()。
传入二进制字符串,翻译成英语句子并返回。
二进制字符串是以空格分隔的。
方法一:
function binaryAgent(str) { var arr = str.split(" "); for(var i in arr){ var num = 0; for (var j = 0; j < arr[i].length; j++) { num += Math.pow(2,7 - j) * Number(arr[i][j]); } arr.splice(i,1,String.fromCharCode(num)); } return arr.join(""); } binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111");
方法二:
function binaryAgent(str) { var arr = str.split(" "); for(var i in arr){ var num = 0; num = parseInt(arr[i],2); arr.splice(i,1,String.fromCharCode(num)); } return arr.join(""); } binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111");
运行结果:Aren't bonfires fun!?
所有的东西都是真的!
完善编辑器中的every函数,如果集合(collection)中的所有对象都存在对应的属性(第二个参数),并且属性(第二个参数)对应的值为真。函数返回ture。反之,返回false。记住:您可以通过点符号或[]符号来访问对象属性。
function every(collection, pre) { // Is everyone being true? var flag = true; for(var i in collection){ if (!collection[i][pre]){ flag = false; break; } } return flag; } every([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex");
运行结果:true
创建一个计算两个参数之和的 function。如果只有一个参数,则返回一个 function,该 function 请求一个参数然后返回求和的结果。
例如,add(2, 3) 应该返回 5,而 add(2) 应该返回一个 function。
调用这个有一个参数的返回的 function,返回求和的结果:
var sumTwoAnd = add(2);
sumTwoAnd(3) 返回 5。如果两个参数都不是有效的数字,则返回 undefined。
运行结果:5function add() { if (arguments.length == 1 && typeof(arguments[0]) != "number") { return undefined; } else if (arguments.length == 1 && typeof(arguments[0]) == "number") { var arg = arguments[0]; return function(num){ console.log(num); if(typeof(num) == "number"){ return arg + num; }else{ return undefined; } } }else{ if(arguments.length){ var sum = 0; for (var i = 0; i < arguments.length; i++) { if (typeof(arguments[i]) == "number") { sum += arguments[i]; } else { sum = undefined; } } return sum; } } } add(2,3);