on
Freecodecamp 算法练习
初级算法
Reverse a String
这个简单,字符串 immutable,先 split 成数组再 reverse,最后 join
function reverseString(str) {
return str.split('').reverse().join('');
}
Factorialize a Number
这个也是,使用 recurse
function factorialize(num) {
if (num === 0) { return 1; }
return num * factorialize(num-1);
}
Check for Palindromes
检测回文,即正反读都是一样的词,基础用法可以如1中检测是否正反相等,高级用法可使用递归
function palindrome(str) {
str = str.toLowerCase().replace(/[^a-z|0-9]/g, "");
if (str.length === 0){
return true;
}
if (str[0] !== str[str.length-1]){
return false;
}
else{
return palindrome(str.slice(1,str.length - 1));
}
}
Find the Longest Word in a String
找出字符串中最长的词的长度,可使用遍历,也可以 reduce,高级用法又用递归
function findLongestWord(str) {
str = str.split(" ");
if(str.length == 1){
return str[0].length;
}
if(str[0].length >= str[1].length){
str.splice(1,1);
return findLongestWord(str.join(" "));
}
if(str[0].length <= str[1].length){
return findLongestWord(str.slice(1,str.length).join(" "));
}
}
Title Case a Sentence
让句中每个单词首字母大写,可用 replace,charAt 调用,高级用法使用 ES6 中的箭头函数(匿名函数),replcae 函数第二参数接收的参数即是此匿名函数。如下
function titleCase(str) {
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => (L).toUpperCase());
}
Return Largest Numbers in Arrays
输出二元数组下各数组中最大的数,可遍历两个数组比较,初始化一个变量存储;高级用法如下
function largestOfFour(arr) {
return arr.map(Function.apply.bind(Math.max, null));
}
Confirm the Ending
进阶的 endwith……,害怕。可用 substring 倒取最后一个
function confirmEnding(str, target) {
return str.substr(-target.length) === target;
}
Repeat a string repeat a string
重复一个字符串多遍,可用 while(num > 0),设置计数;以下方法调用了 repeat,使用的 test ? true : false 为三元条件运算。
function repeatStringNumTimes(str, num) {
return num > 0 ? str.repeat(num) : '';
}
Truncate a string
缩短文本用…代替;基本使用 slice 实现
function truncateString(str, num) {
if (str.length <= num) {
return str;
} else {
return str.slice(0, num > 3 ? num - 3 : num) + '...';
}
}
Chunky Monkey
按照第二个参数划分第一个数组参数,以下为高级用法
function chunkArrayInGroups(arr, size) {
var newArr = [];
var i = 0;
while (i < arr.length) {
newArr.push(arr.slice(i, i+size));
i += size;
}
return newArr;
}
Slasher Flick
类似上一个,数组中只保留第二个参数之后的内容;直接用 slice 即可
function slasher(arr, howMany) {
return arr.slice(howMany);
}
Mutations
检测第一个参数是否完全包含第二个参数,只需包含其元素;以下用法使用了 split,every,indexOf
function mutation(arr) {
return arr[1].toLowerCase()
.split('')
.every(function(letter) {
return arr[0].toLowerCase()
.indexOf(letter) != -1;
});
}
Falsy Bouncer
除掉假值,使用 filter
function bouncer(arr) {
return arr.filter(Boolean);
}
Seek and Destroy
类似上题,只返回不包含后几个参数的原数组
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments);
args.splice(0, 1);
return arr.filter(function(element) {
return args.indexOf(element) === -1;
});
}
Where do I belong
将第二个参数插入数组,排序然后返回索引
function getIndexToIns(arr, num) {
var index = arr.sort((curr, next) => curr > next)
.findIndex((currNum)=> num <= currNum);
return index === -1 ? arr.length : index;
}
Caesars Cipher
凯撒密码,把字符前后移动生成密文,以下用法使用了 fromCharCode,charCodeAt
function rot13(str) {
return str.replace(/[A-Z]/g, (L) => String.fromCharCode(65 + (L.charCodeAt(0) - 65 + 13) % 26));
}
中级算法
Sum All Numbers in a Range
返回数组参数内的所有整数和,下列用法用到了展开运算符
function sumAll(arr) {
var sum = 0;
for (var i = Math.min(...arr); i <= Math.max(...arr); i++){
sum += i;
}
return sum;
}
Diff Two Arrays
返回两行中不公有的元素,以下函数调用了 filter,concat,includes
function diffArray(arr1, arr2) {
return arr
.filter(el => !arr2.includes(el))
.concat(
arr2.filter(el => !arr1.includes(el))
)
}
Roman Numeral Converter
对应阿拉伯数字对应罗马数字
var convertToRoman = function(num) {
var decimalValue = [ 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ];
var romanNumeral = [ 'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I' ];
var romanized = '';
for (var index = 0; index < decimalValue.length; index++) {
while (decimalValue[index] <= num) {
romanized += romanNumeral[index];
num -= decimalValue[index];
}
}
return romanized;
}
Wherefore art thou
返回第二个参数作为值在第一个参数的数组,使用了 Object.key() 返回键
function whatIsInAName(collection, source) {
var srcKeys = Object.keys(source);
return collection.filter(function (obj) {
return srcKeys.reduce(function (res, key) {
return obj.hasOwnProperty(key) && obj[key] === source[key];
}, false);
});
}
Search and Replace
查找替换……
function myReplace(str, before, after) {
function applyCasing(source, target) {
var targetArr = target.split("");
var sourceArr = source.split("");
for (var i = 0; i < Math.min(targetArr.length, sourceArr.length); i++){
if (/[A-Z]/.test(sourceArr[i])) {
targetArr[i] = targetArr[i].toUpperCase();
}
else targetArr[i] = targetArr[i].toLowerCase();
}
return (targetArr.join(""));
}
return str.replace(before, applyCasing(before, after));
}
Pig Latin
元音开始的单词词尾加 way,非元音开头的将元音以前的移到最后加ay,解法如下
function translatePigLatin(str) {
var strArr = [];
var tmpChar;
function isConsonant(char) {
return !/[aeiou]/.test(char);
}
if (!isConsonant(str.charAt(0)))
return str + "way";
else
strArr = str.split("");
while (isConsonant(strArr[0])) {
tmpChar = strArr.shift();
strArr.push(tmpChar);
}
return strArr.join("")+"ay";
}
DNA Pairing
DNA 配对,定义数组对应键查找值
function pairElement(str) {
var map = {T:'A', A:'T', G:'C', C:'G'};
strArr = str.split('');
for (var i=0;i<strArr.length;i++){
strArr[i]=[strArr[i], map[strArr[i]]];
}
return strArr;
}
Missing letters
指定一段连续的字母,输出中间漏掉的;调用 fromCharCode 和 charCodeAt,类似初级16题
function fearNotLetter(str) {
var allChars = '';
var notChars = new RegExp('[^'+str+']','g');
for (var i = 0; allChars[allChars.length-1] !== str[str.length-1] ; i++)
allChars += String.fromCharCode(str[0].charCodeAt(0) + i);
return allChars.match(notChars) ? allChars.match(notChars).join('') : undefined;
}
Boo who
检验是否为布尔值,输出 true 或 false
function booWho(bool) {
return typeof bool === 'boolean';
}
Sorted Union
合并并去重二重数组;以下为神之解法……
function uniteUnique() {
var concatArr = [];
var i = 0;
while (arguments[i]){
concatArr = concatArr.concat(arguments[i]); i++;
}
uniqueArray = concatArr.filter(function(item, pos) {
return concatArr.indexOf(item) == pos;
});
return uniqueArray;
}
Convert HTML Entities
HTML 特殊符号对应及转义;使用 object 存储,然后对应查找值,也使用 map 调用了函数返回数组
function convertHTML(str) {
htmlEntities={
'&':'&',
'<':'<',
'>':'>',
'\"':'"',
'\'':"'"
};
return str.split('').map(function(entity){
return htmlEntities[entity] || entity;
}).join('');
}
Spinal Tap Case
断词改用连字符,用到了正则捕获组
function spinalCase(str) {
str = str.replace(/([a-z])([A-Z])/g, '$1 $2');
return str.toLowerCase().split(/(?:_| )+/).join('-');
}
Sum All Odd Fibonacci Numbers
返回小于参数的所有奇数的 fibonacci 数的和,使用了 reduce 累加
function sumFibs(num) {
var arrFib = [1];
for (var i = 1; i <=num;) {
arrFib.push(i);
i = arrFib[arrFib.length - 1] + arrFib[arrFib.length - 2];
}
var res = arrFib.reduce(function(prev, curr) {
if (curr%2 !== 0) return prev + curr;
else return prev;
});
return res;
}
Sum All Primes
对小于参数的质数求和,嵌套函数并使用递归
function sumPrimes(num) {
function isPrime(number){
for (i = 2; i <= number; i++){
if(number % i === 0 && number!= i){
return false;
}
}
return true;
}
if (num === 1){
return 0;
}
if(isPrime(num) === false){
return sumPrimes(num - 1);
}
if(isPrime(num) === true){
return num + sumPrimes(num - 1);
}
}
Smallest Common Multiple
取 array 间所有数的最小公倍数
function smallestCommons(arr) {
var range = [];
for (var i = Math.max(arr[0], arr[1]); i >= Math.min(arr[0], arr[1]); i--) {
range.push(i);
}
return range.reduce(function(previousValue, currentValue) {
var gcdPrevCurr = gcd(previousValue, currentValue);
return (previousValue * currentValue) / gcdPrevCurr;
});
function gcd(x, y) {
if (y === 0)
return x;
else
return gcd(y, x%y);
}
}
Finders Keepers
返回满足函数的数组中第一个为真的值,直接使用 filter
function findElement(arr, func) {
filterArr = arr.filter(func);
return filterArr[0];
}
Drop it
返回满足函数的数组中元素;调用了 shift,这解法简直……
function dropElements(arr, func) {
while(arr.length > 0 && !func(arr[0])) {
arr.shift();
}
return arr;
}
Steamroller
抽取多层数组中的元素返回;使用递归,厉害厉害
function steamrollArray(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? steamrollArray(toFlatten) : toFlatten);
}, []);
}
Binary Agents
解析二进制;调用了fromCharCode,parseInt,用以解析字符串
function binaryAgent(str) {
return String.fromCharCode(...str.split(" ").map(function(char){ return parseInt(char, 2); }));
}
Everything Be True
检验第二个参数是否存在于所传入的数组,解法厉害
function truthCheck(collection, pre) {
return collection.reduce(function(acc, next) {
if (next[pre]) {
return acc;
}
else {
acc = false;
return acc;
}
},true);
}
Arguments Optional
传入参数求和,若参数只有一个则返回函数接收第二个数,解法厉害
function addTogether() {
var args = Array.from(arguments);
return args.some(n => typeof n !== 'number') ? undefined: args.length > 1 ?
args.reduce((acc, n) => acc += n, 0): (n) => typeof n === "number" ? n + args[0]: undefined;
}
高级算法
Validate US Telephone Numbers
验证美国电话号码,神长的正则……
function telephoneCheck(str) {
var regex = /^(1\s?)?(\(\d{3}\)|\d{3})[\s\-]?\d{3}[\s\-]?\d{4}$/;
return regex.test(str);
}
Symmetric Difference
对称差或者异或,即筛掉数组公有的元素,解法头疼
function sym() {
const diff = (A, B) => new Set([...A].filter(n => !B.has(n)));
const result = [...arguments]
.map(arr => new Set(arr))
.reduce((acc, set) => new Set([...diff(acc, set), ...diff(set, acc)]));
return [...result];
}
Exact Change
找零钱的函数……神长
var denom = [
{ name: 'ONE HUNDRED', val: 100.00},
{ name: 'TWENTY', val: 20.00},
{ name: 'TEN', val: 10.00},
{ name: 'FIVE', val: 5.00},
{ name: 'ONE', val: 1.00},
{ name: 'QUARTER', val: 0.25},
{ name: 'DIME', val: 0.10},
{ name: 'NICKEL', val: 0.05},
{ name: 'PENNY', val: 0.01}
];
function checkCashRegister(price, cash, cid) {
var change = cash - price;
var register = cid.reduce(function(acc, curr) {
acc.total += curr[1];
acc[curr[0]] = curr[1];
return acc;
}, {total: 0});
if (register.total === change) {
return 'Closed';
}
if (register.total < change) {
return 'Insufficient Funds';
}
var change_arr = denom.reduce(function(acc, curr) {
var value = 0;
while (register[curr.name] > 0 && change >= curr.val) {
change -= curr.val;
register[curr.name] -= curr.val;
value += curr.val;
change = Math.round(change * 100) / 100;
}
if (value > 0) {
acc.push([ curr.name, value ]);
}
return acc; // Return the current Change Array
}, []);
if (change_arr.length < 1 || change > 0) {
return "Insufficient Funds";
}
return change_arr;
}
Inventory Update
更新存货,使用了 forEach,对数组调用参数
function updateInventory(arr1, arr2) {
var flag = 0;
arr2.forEach(function(item) {
flag = 0;
arr1.forEach(function(list) {
if(item[1] === list[1]) {
list[0] += item[0];
flag = 1;
}
});
if(flag === 0)
arr1.push(item);
});
return arr1.sort(function(a, b) {
return a[1] > b[1] ? 1 : -1;
});
}
No repeats please
返回排列组合不连续重复的数目,不是很懂
function permAlone(str) {
var regex = /(.)\1+/g;
var arr = str.split('');
var permutations = [];
var tmp;
if (str.match(regex) !== null && str.match(regex)[0] === str) return 0;
function swap(index1, index2) {
tmp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = tmp;
}
function generate(int) {
if (int === 1) {
permutations.push(arr.join(''));
} else {
for (var i = 0; i != int; ++i) {
generate(int - 1);
swap(int % 2 ? 0 : i, int - 1);
}
}
}
generate(arr.length);
var filtered = permutations.filter(function(string) {
return !string.match(regex);
});
return filtered.length;
}
Friendly Date Ranges
输入两个时间点,返回友好……的时间段
function makeFriendlyDates(str) {
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
function convertDate(str) {
var dateStr = str.split('-');
return (new Date(Date.UTC(dateStr[0], dateStr[1] - 1, dateStr[2])));
}
function dateEnding(val) {
switch (val) {
case 1:
case 21:
case 31:
return val + 'st';
case 2:
case 22:
return val + 'nd';
case 3:
case 23:
return val + 'rd';
default:
return val + 'th';
}
}
function monthDiff(date1, date2) {
var month2 = date2.getUTCFullYear() * 12 + date2.getUTCMonth();
var month1 = date1.getUTCFullYear() * 12 + date1.getUTCMonth();
return month2 - month1;
}
function dayDiff(date1, date2) {
if(date2.getUTCMonth() === date1.getUTCMonth()){
return date1.getUTCDate()-date2.getUTCDate();
}
return 0;
}
function getMonth(date) {
return months[date.getUTCMonth()];
}
function displayDate() {
if (date2.getTime() - date1.getTime() === 0) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()) + ', ' + date1.getUTCFullYear()];
}
if (date1.getUTCMonth() === date2.getUTCMonth() && date1.getUTCFullYear() === date2.getUTCFullYear()) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()), dateEnding(date2.getUTCDate())];
}
if (monthDiff(date1, date2) < 12 && date1.getUTCFullYear() !== date2.getUTCFullYear() ) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}
if (monthDiff(date1, date2) <= 12 && dayDiff(date1, date2)>0) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate())+', '+date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}
if (monthDiff(date1, date2) < 12) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate())+', '+date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()) + ', ' + date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate()) + ', ' + date2.getUTCFullYear()];
}
var date1 = convertDate(str[0]);
var date2 = convertDate(str[1]);
return displayDate();
}
Make a Person
简单的类操作,善用 this
var Person = function(firstAndLast) {
var fullName = firstAndLast;
this.getFirstName = function() {
return fullName.split(" ")[0];
};
this.getLastName = function() {
return fullName.split(" ")[1];
};
this.getFullName = function() {
return fullName;
};
this.setFirstName = function(name) {
fullName = name + " " + fullName.split(" ")[1];
};
this.setLastName = function(name) {
fullName = fullName.split(" ")[0] + " " + name;
};
this.setFullName = function(name) {
fullName = name;
};
};
Map the Debris
返回轨道周期,使用 forEach,参数中使用了 object
function orbitalPeriod(arr) {
var GM = 398600.4418;
var earthRadius = 6367.4447;
arr.forEach(function(item) {
var tmp = Math.round(2 * Math.PI * Math.sqrt(Math.pow(earthRadius + item.avgAlt, 3) / GM));
delete item.avgAlt;
item.orbitalPeriod = tmp;
});
return arr;
}
Pairwise
从第一个数组里面所有任意两个数和为第二个,返回索引和
function pairwise(arr, arg) {
var pairArr = arr.slice();
return pairArr.reduce( function (a,b,index){
var search = arg - b;
if ( pairArr.indexOf(search) != -1 && pairArr.indexOf(search) != index ){
var total = index + pairArr.indexOf(search);
pairArr.splice(index,1,NaN);
pairArr.splice(pairArr.indexOf(search),1,NaN);
return a + total;
}
return a;
},0);
}