比较字符串 (Mutations)
题目:www.freecodecamp.cn/challenges/…
如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回 true 。 举例,["hello", "Hello"]应该返回 true,因为在忽略大小写的情况下,第二个字符串的所有字符都可以在第一个字符串找到。
思路:
- 因为忽略大小写,所以我们全部转成小写字母:
String.toLowerCase()
- 然后找字符串是否存在字符:
String.indexOf()
- 遍历
function mutation(arr) {
const s1 = arr[0].toLowerCase()
const s2 = arr[1].toLowerCase()
let result = true
for (let i of s2) {
if (s1.indexOf(i) === -1) {
result = false
return result
}
}
return result;
}
mutation(["hello", "hey"]);
// 可以不用 result
function mutation(arr) {
const s1 = arr[0].toLowerCase()
const s2 = arr[1].toLowerCase()
for (let i of s2) {
if (s1.indexOf(i) === -1) {
return false
}
}
return true
}
mutation(["hello", "hey"])
复制代码
博客的思路:利用 filter
function mutation(arr) {
var sourceStr = arr[0].toLowerCase();
var targetArr = arr[1].toLowerCase().split("");
var filteredArr = targetArr.filter(function (char) {
return sourceStr.indexOf(char) === -1;
})
return filteredArr.length === 0;
}
复制代码
filter
的思路就是利用数组的遍历,那么我们也可以用数组的 every
呀
// 试一试
function mutation(arr) {
const s = arr[0].toLowerCase()
const a = arr[1].toLowerCase().split('')
return a.every(item => s.indexOf(item) !== -1)
}
// 简洁点
function mutation(arr) {
return arr[1].toLowerCase().split('').every(item => arr[0].toLowerCase().indexOf(item) !== -1)
}
mutation(["hello", "hey"]);
复制代码
过滤数组假值 (Falsy Bouncer)
删除数组中的所有假值。
思路: 遍历数组的元素,判断是否为真,为真的话放进一个数组内,最后返回该数组。
function bouncer(arr) {
return arr.reduce((arr, item) => item ? arr.concat(item) : arr, [])
}
bouncer([7, "ate", "", false, 9]);
复制代码
后面想想,上一题的 filter
,这里更应该用过滤的
function bouncer(arr) {
return arr.filter(item => item)
// 博客里的是用了 !! 去做隐式转换,不知道有没有必要这样做。
// return arr.filter
}
bouncer([7, "ate", "", false, 9]);
// 然后 Boolean 是接受一个参数返回布尔值的构造函数,filter 接受的也是一个函数,该函数返回布尔值。
const bouncer = arr => arr.filter(Boolean)
复制代码
摧毁数组 (Seek and Destroy)
// 初次解法
function destroyer(...arr) {
const a1 = arr[0]
const a2 = arr.slice(1)
return a1.reduce((arr, val) => a2.indexOf(val) === -1 ? arr.concat(val) : arr, [])
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
复制代码
再理解下题意,发现应该用的是 filter
function destroyer(...arr) {
const a1 = arr[0]
const a2 = arr.slice(1)
return a1.filter(item => a2.indexOf(item) === -1)
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
复制代码
数组排序并找出元素索引 (Where Do I belong)
题意: 一个数组,一个数字,然后这个数字在这个数组中,按小到大排序,它的下标应该是多少。
解法一:
- 把数字添加到数组中
push, concat
- 排序新的数组
sort
- 找数组的位置
indexOf, findIndex
note:
indexOf
:expects a value as first parameter.findIndex
:expects a callback as first parameter.- 如果是复杂的查找的话就用
findIndex
,比如是查找item.xx
这样的话就要用findIndex
function where(arr, num) {
arr.push(num)
arr.sort((a, b) => a - b)
return arr.indexOf(num)
}
where([40, 60], 50);
复制代码
解法二:不去排序,我们去遍历,然后计数
function where(arr, num) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] < num) {
count++;
}
}
return count;
}
where([40, 60], 50);
// 同样是遍历,只不过用的是 filter
function where(arr, num) {
return arr.filter(item => item < num).length;
}
// 当然你用 map, reduce 也行,map 麻烦一些,其实还是用了遍历 + 计数的方式
const where = (arr, num) => arr.reduce((acc, item) => item > num ? acc.concat(item) : acc, []).length
where([40, 60], 50);
复制代码
凯撒密码 (Caesars Cipher)
题意: 给你一个大写字母的字符串,然后你把字符串的每一个字母向右移动13位,超出了再循环回来,组成一个新的字符串返回。
需要用到的:
-
String.charCodeAt()
-
String.fromCharCode()
-
分割成数组再遍历,最后拼接字符串
function rot13(str) { // LBH QVQ VG!
var arr = str.split('');
return arr.map(item => /[A-Z]/.test(item) ? String.fromCharCode(item.charCodeAt() % 26 + 65) : item).join('');
}
rot13("SERR PBQR PNZC"); // 你可以修改这一行来测试你的代码
// /[A-Z]/.test(item) 只替换大写字符
// item.charCodeAt() % 26 + 65 只是因为 'A'.charCodeAt() => 65, x % n = [0, n - 1]
复制代码
replace()
替换
function rot13(str) { // LBH QVQ VG!
return str.replace(/[A-Z]/g, char => {
return String.fromCharCode(char.charCodeAt() % 26 + 65)
})
}
rot13("SERR PBQR PNZC"); // 你可以修改这一行来测试你的代码
复制代码
给定范围内的数字总和 (Sum All Numbers in a Range)
题意:给一个数组,然后返回给定范围的数字总和。
例如:[1, 4] => 1+2+3+4=10 返回 10
数学公式解法:n + n+1 + n+2 + ... + m = (n+m)(m-n+1)/2 = (m^2-n^2+n+m)/2
function sumAll(arr) {
var a = arr[0], b = arr[1];
return (Math.abs(a*a - b*b) + a+b) / 2;
}
sumAll([1, 4]);
复制代码
循环叠加解法:首先要判断两数的大小,再循环叠加
function sumAll(arr) {
var a = arr[0], b = arr[1], result = 0;
if (a > b) {
// 交换
[a, b] = [b, a];
}
while(b >= a) {
result += a;
a++;
}
return result;
}
sumAll([1, 4]);
复制代码
博客的另一种解法:生成一个数组[n, n+1, n+2, ... , m],再遍历求和。
function sumAll(arr) {
var numArr = Array.from({length: Math.abs(arr[0] - arr[1]) + 1}, (_, i) => i + Math.min.apply(null, arr));
return numArr.reduce((prev, next) => prev + next);
}
// 上面每次都要拿一次最小值,其实可以提取出来的
// 也可以用 Array() + Array.fill()
function sumAll(arr) {
var min = Math.min(...arr); // var min = Math.min.apply(null, arr);
var numArr = Array(Math.abs(arr[0] - arr[1]) + 1).fill(min);
return numArr.reduce((acc, val, index) => acc + val + index);
}
复制代码
比较两数组差异 (Diff Two Arrays)
题意:比较两个数组,然后返回一个新数组,该数组的元素为两个给定数组中所有独有的数组元素。换言之,返回两个数组的差异。
按照数学上集合来讲就是,两个集合并集减去它们的交集。
function diff(arr1, arr2) {
var sum = [...new Set([...arr1, ...arr2])];
return sum.filter(item => arr1.indexOf(item) === -1 || arr2.indexOf(item) === -1);
}
diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);
复制代码
上面那个感觉有点麻烦,又是拼接数组,又是集合转数组,虽然可以去除,但是看起来复杂了。
可以直接拼接数组再过滤就行了。
function diff(arr1, arr2) {
return arr1.concat(arr2).filter(item => arr1.indexOf(item) === -1 || arr2.indexOf(item) === -1)
}
diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);
复制代码
找出对象包含的特定键值对 (Where art thou)
题意:
- 给你一个对象数组,还有一个对象
- 数组里的对象都包含第二个参数里的对象,还有键值相等
- 返回一个过滤后的数组
// 首先返回的是数组,那么用 filter
// 其次是数组的元素里要包含对象的键值 Object.keys(obj) 返回给对对象可枚举属性(key)的字符串数组。
// 为什么是字符串数组,因为对象属性都会转为字符串。
function where(collection, source) {
return collection.filter(item => Object.keys(source).every(key => source[key] === item[key]));
}
where([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
复制代码
句中查找替换 (Search and Replace)
题意:
- 使用给定的参数对句子执行一次查找和替换,然后返回新句子。
- 第一个参数是将要对其执行查找和替换的句子。
- 第二个参数是将被替换掉的单词(替换前的单词)。
- 第三个参数用于替换第二个参数(替换后的单词)。
- 注意:替换时保持原单词的大小写。例如,如果你想用单词 "dog" 替换单词 "Book" ,你应该替换成 "Dog"。
思路一:
- 句子分割成一个个单词
- 判断被替换的单词是否首字母大写,修改替换的单词
- 找到被替换的单词并替换掉
- 再拼接成字符串
function myReplace(str, before, after) {
var arr = str.split(' ');
if (before.slice(0, 1).charCodeAt() < 91) {
// 判断条件用正则表达式也ok /[A-Z]/.test(before[0])
after = after[0].toUpperCase() + after.slice(1);
}
arr.splice(arr.indexOf(before), 1, after);
return arr.join(' ');
}
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
复制代码
思路二:直接字符串替换
- 首先看被替换的字符串首字母是否大写,是的话修改替换的字符串
- 匹配替换
function myReplace(str, before, after) {
if (/[A-Z]/.test(before[0])) {
after = after[0].toUpperCase() + after.slice(1);
}
return str.replace(before, after);
}
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
复制代码
DNA 配对 (DNA Pairing)
题目意思就是:给你一段残缺的碱基,返回一段碱基对,碱基对有:A => T,C => G
输入:GCG 输出:[["G", "C"], ["C","G"],["G", "C"]]
思路:
- 好像没有什么可以优化的,感觉就是写死的。
- 因为返回的是数组,那么我们先把字符串转变为数组。然后字符串长度多少,返回的数组长度就为多少,所以可以用
map
去遍历生成新数组。 - 之后就是数组去填充的内容了,怎么对应上,我们用一个对象去存储。
// 这样的话,取的时候方便一些
var obj = {
'A': ['A', 'T'],
'T': ['T', 'A'],
'C': ['C', 'G'],
'G': ['G', 'C']
};
// 这样的话就要拼接
var obj = {
A: 'T',
T: 'A',
C: 'G',
G: 'C'
}
复制代码
function pair(str) {
// 这个对象的属性可以不同加引号,它会自动转换为字符串的。
var obj = {
A: ['A', 'T'],
T: ['T', 'A'],
C: ['C', 'G'],
G: ['G', 'C']
};
return str.split('').map(function(item) {
return obj[item];
});
}
pair("GCG");
function pair(str) {
var obj = {
A: 'T',
T: 'A',
C: 'G',
G: 'C'
};
return str.split('').map(function(item) {
return [item, obj[item]];
});
}
pair("GCG");
复制代码