Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeCodeCamp 算法题 #5

Open
tiu5 opened this issue May 17, 2019 · 21 comments
Open

FreeCodeCamp 算法题 #5

tiu5 opened this issue May 17, 2019 · 21 comments

Comments

@tiu5
Copy link
Owner Author

tiu5 commented May 17, 2019

翻转字符串 (Reverse a String)

参考博客:http://singsing.io/blog/fcc/basic-reverse-a-string/

题目要求:输入 'hello' 输出 'olleh'

思路一:

  • 利用 Array.reverse() 进行反转
  • 利用 String.split() 进行 String => Array
  • 需要输出 String, 所以还要 Array.join() 进行 Array => String
function reverseString(str) {
  // 请把你的代码写在这里
  return str.split('').reverse().join('')
}
reverseString("hello"); // "olleh"

思路二:利用 for 循环遍历

  • String[index] 跟数组一样,有下标由 0 开始,ES5语法
  • String.charAt(i) 这个则是 ES3语法
function reverseString(str) {
  let result = ''
  for(let i = str.length - 1; i >= 0; i--) {
    result += str[i]
  }
  return result
}
reverseString("hello"); // "olleh"

思路三: 利用递归

function reverseString(str) {
  if (str.length === 1) {
    return str
  } else {
    return reverseString(str.substr(1)) + str[0]
  }
}
reverseString("hello"); // "olleh"
// 注意:递归涉及到两个因素,递归调用以及弹出过程。reverseString(str.substr(1)) 就是递归调用,+ str[0] 就是弹出过程

@tiu5
Copy link
Owner Author

tiu5 commented May 17, 2019

计算一个整数的阶乘 (Factorialize a Number)

参考博客:http://singsing.io/blog/fcc/basic-factorialize-a-number/
题目地址:https://www.freecodecamp.cn/challenges/factorialize-a-number

计算一个整数的阶乘
如果用字母 n 来代表一个整数,阶乘代表着所有小于或等于n的整数的乘积。
阶乘通常简写成 n!
例如: 5! = 1 * 2 * 3 * 4 * 5 = 120

即:function (num) => num!

  • 传统思路 while 循环
// 利用 while 循环
function factorialize(num) {
  var result = 1;
  while(num > 1) {
    result *= num;
    num--;
  }
  return result;
}

factorialize(5); // 120
  • 可不可以看成是一个累计数?
// 利用 reduce
// Array(num):新建一个数组 num 代表 length
// Array.fill(0):数组元素全部赋值为 0
// Array.map(fn): 遍历函数每个元素,回调函数返回的作为新的数组的值
// reduce(fn, initialAcc): 一个累计器
// 回调函数 fn(acc, val, index, array) acc 为累计值, val 为当前项的值, index 下标, array 原来的数组
// initialAcc 为 acc 的初始值,若无则默认为数组的第一项的值

const factorialize = num => Array(num).fill(0).map((value, index) => index + 1).reduce((acc, val) => acc *= val, 1)
factorialize(5) // 120
  • 这个应该可以用递归
function factorialize(num) {
  if (num > 1) {
    return factorialize(num - 1) * num;
  } else {
    return 1;
  }
}

factorialize(5); // 120

// 好像这种比较简洁
function factorialize(num) {
  // 初始及弹出条件
  if (num === 0) {
    return 1;
  }
  // 递归调用
  return num * factorialize(num - 1)
}

@tiu5
Copy link
Owner Author

tiu5 commented May 18, 2019

检查回文字符串 (Check for Palindromes)

题目:https://www.freecodecamp.cn/challenges/check-for-palindromes
参考博客:http://singsing.io/blog/fcc/basic-check-for-palindromes/

首先回文字符串的意思就是字符串正着读和反着读是一样的。
比如:

  • aba 反转得到 aba,两者相同,return true
  • abc 反转得到 cba,abc != cba,return false

然后字符串忽略大小写,忽略标点符号,空格:所以我们可以把忽略的标点符号和空格都替换掉,替换成空串(''),也可以看作是删掉标点符号和空格。

我们用到的替换字符串:String.replace(regexp|substr, newSubStr|function)

  • 第一个参数是匹配的子串,可以是一个正则表达式,也可以是一个字符串
  • 第二个参数是替换的字符串,可以是一个字符串,也可以是一个函数返回的字符串

然后正则表达式匹配是可以用$1, $2

// 交换字符串中的两个单词
var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
// Smith, John
console.log(newstr);

然后忽略大小写,我们统一转为小写:String.toLowerCase()这时候得到的就是一个有效的字符串。
这时候我们要反转字符串,简单的方法就是利用Array.reserve()去反转。

function palindrome(s) {
  const str =  s.replace(/[^a-zA-Z0-9]/g,'').toLowerCase() // 记得要加上g 全局匹配
  const strReverse = str.split('').reverse().join('')
  return str === strReverse
}

@tiu5
Copy link
Owner Author

tiu5 commented May 19, 2019

找出最长单词 (Find the Longest word in a String)

题目:https://www.freecodecamp.cn/challenges/find-the-longest-word-in-a-string
参考博客:http://singsing.io/blog/fcc/basic-find-the-longest-word-in-a-string/

思路是这样的:

  1. 分割成一个个单词,字符串分割:String.split()
  2. 然后遍历所有单词的长度,找出最大的,并返回该数值,字符串长度:String.length

我的代码:

function findLongestWord(str) {
  return str.split(' ').reduce((acc, val) => acc = acc < val.length ? val.length : acc, 0)
}

findLongestWord("The quick brown fox jumped over the lazy dog")

第一步:分割字符串基本没办法优化,所以不同的解法基本在第二步,找出一个数组中的最大值。为什么说是一个数组中的最大值呢,因为字符串分割后就变成了数组。

我的解法就是普通的,冒泡排序,遍历一次拿到最大值。

多种解法也就是在变相考如果求数组中最大的值:

  • array.reduce((acc, val) => acc > val ? acc : val)
  • Math.max.apply(null, array)
  • array.sort((a, b) => b - a)[0]

进而有

// 结合 Math.max(a, b) 会返回 a, b 间最大的值
function findLongestWord(str) {
  // 第一版写法
  // return str.split(' ').reduce((acc, val) => acc = acc < val.length ? val.length : acc, 0)
  
  // 可以不用给 acc 赋值
  // return str.split(' ').reduce((acc, val) => acc < val.length ? val.length : acc, 0)
  
  // 结合 Math.max()
  return str.split(' ').reduce((a, b) => Math.max(a, b.length), 0)
}


// Math.max.apply(null, array)
function findLongestWord(str) {
  return Math.max.apply(null, str.split(' ').map(item => item.length))
}

// Math.max + ...扩展运算符
function findLongestWord(str) {
  return Math.max(...str.split(' ').map(item => item.length))
}

findLongestWord("The quick brown fox jumped over the lazy dog")

// array.sort((a, b) => b - a)[0]
function findLongestWord(str) {
  return str.split(' ').map(item => item.length).sort((a, b) => b - a)[0]
}

findLongestWord("The quick brown fox jumped over the lazy dog")

另外:Math.max() 使用 apply 和 ...扩展运算符的局限:当数组过大时,可能会出错。这是因为函数的参数长度限制,在标准里头:Argument length limited to 65536,当然不同浏览器可能不一样。

However, both spread (...) and apply will either fail or return the wrong result if the array has too many elements, because they try to pass the array elements as function parameters. See Using apply and built-in functions for more details. The reduce solution does not have this problem.

@tiu5
Copy link
Owner Author

tiu5 commented May 19, 2019

句中单词首字母大写 (Title Case a Sentence)

题目:https://www.freecodecamp.cn/challenges/title-case-a-sentence
参考博客:http://singsing.io/blog/fcc/basic-title-case-a-sentence/

// 这是我最初的想法
function titleCase(str) {
  return str.toLowerCase().split(' ').map(item => item.replace(item[0], item[0].toUpperCase())).join(' ');
}

titleCase("I'm a little tea pot");

参考了博客的内容后,发现直接用String.replace()就可以了。博客里的其他遍历的方法,基本也是跟我类似的。
只是我用的是replace去替换,他里面用的是slice分割拼接
即:String.replace(item[0], item[0].toUpperCase())也可以换成String[0] + String.slice(1)

正则表达式,参考资料:https://github.com/KRISACHAN/front-end-project/tree/master/learning/regexp-JS

  • ()代表分组,多次匹配
  • \s代表匹配任何空白字符,所以适用于匹配空格
  • ^代表匹配开头
  • [a-z]代表匹配小写字母的任意一个
  • g全局匹配

需求:

  • 匹配开头为小写字母的,或者开头为空白字符+小写字母 => /(\s|^)[a-z]/g
  • 替换成大写字母:toUpperCase() 要使用函数item => item.toUpperCase()不能直接用 '$1'.toUpperCase()
  • 另外toUpperCase会忽略掉不能转换的东西,比如特殊字符、大写字符和空格

最终代码:

function titleCase(str) {
  return str.toLowerCase().replace(/(\s|^)[a-z]/g, item => item.toUpperCase())
 }
titleCase("I'm a little tea pot");

@tiu5
Copy link
Owner Author

tiu5 commented May 20, 2019

找出多个数组中的最大数 (Return Largest Numbers in Arrays)

题目:https://www.freecodecamp.cn/challenges/return-largest-numbers-in-arrays
博客:http://singsing.io/blog/fcc/basic-return-largest-numbers-in-arrays/

思路:

  • 基本就是之前找出单词最长的,并返回
  • 只是这个题,不止找出一个数组的最大值,而是找出多个数组的最大值并组成一个数组,这时候用 Array.map() 最合适
// 初次解法
Array.map() 最合适
function largestOfFour(arr) {
  return arr.map(item => Math.max(...item));
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

结合我们之前那个找出最长单词

  • Math.max.apply(null, array)
  • Array.sort((a, b) => b - a)[0]
// Math.max.apply(null, array)
function largestOfFour(arr) {
  return arr.map(item => Math.max.apply(null, item));
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

// Array.sort((a, b) => b - a)[0]
function largestOfFour(arr) {
  return arr.map(item => item.sort((a, b) => b - a)[0]);
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

然后我们可以利用 Array.reduce() 去实现一个 Array.map() 所以也可以这样写:

// Array.reduce() 实现 Array.map() + Math.max()
function largestOfFour(arr) {
  return arr.reduce((acc, val) => acc.concat(Math.max(...val)), []);
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

// 为什么用的是 concat() 而不是 push()
// 因为 concat() 返回的是一个数组,而 push() 返回的是 Array.length
// 使用 push() 的话,我们要手动 return acc 值
// 像这样,不然的话会报错,push is not a function
function largestOfFour(arr) {
  return arr.reduce((acc, val) => {
    acc.push(Math.max(...val))
    return acc
  }, []);
}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

@tiu5
Copy link
Owner Author

tiu5 commented May 20, 2019

检查字符串结尾 (Confirm the Ending)

题目:https://www.freecodecamp.cn/challenges/confirm-the-ending
博客:http://singsing.io/blog/fcc/basic-confirm-the-ending/

思路:

  • 它要比较的是 str 最后的部分和 target 的部分
  • 我们能不能从 str 后面截取跟 target 一样长的字符串
  • 我记得 slice() 是可以反向截取的,例如 取数组最后一个元素:Array.slice(-1)
// 初次解法
function confirmEnding(str, target) {
  return target === str.slice(-target.length);
}

confirmEnding("Bastian", "n");

上面的是反向截取,如果我们要正向截取呢,那我们要知道从第几位开始。str.lengthtarget.length 相减就 ok 了

比较 slice, substr, substring

  • str.slice(beginSlice[, endSlice]) 截取字符串的一部分,返回作为一个新的字符串,不影响原字符串。
    • beginSlice 默认为 0 ,当为负数时,会加上字符串长度。
    • endSlice 默认为字符串长度,当为负数时,会加上字符串长度。
  • str.substr(start[, length]) 返回一个字符串中从指定位置开始到指定字符数的字符。
    • start 默认为 0 ,当为负数时,会加上字符串长度。
  • str.substring(indexStart[, indexEnd])
    • 如果 indexStart 等于 indexEnd,substring 返回一个空字符串。
    • 如果省略 indexEnd,substring 提取字符一直到字符串末尾。
    • 如果任一参数小于 0 或为 NaN,则被当作 0。
    • 如果任一参数大于 stringName.length,则被当作 stringName.length。
    • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。
// slice
function confirmEnding(str, target) {
  return target === str.slice(str.length - target.length);
}

confirmEnding("Bastian", "n");
// substr
function confirmEnding(str, target) {
  return target === str.substr(str.length - target.length);
}

confirmEnding("Bastian", "n");
// substring
function confirmEnding(str, target) {
  return target === str.substr(str.length - target.length);
}

confirmEnding("Bastian", "n");

利用正则表达式,这个真没想过!

  • RegExp 创建了一个正则表达式对象,用于将文本与一个模式匹配。
  • $ 代表从后面匹配
  • RegExp.test() 测试当前正则是否能匹配目标字符串
function confirmEnding(str, target) {
  return RegExp(`${target}$`).test(str)
}

confirmEnding("Bastian", "n");

@tiu5
Copy link
Owner Author

tiu5 commented May 22, 2019

重复输出字符串 (Repeat a string repeat a string)

题目:https://www.freecodecamp.cn/challenges/repeat-a-string-repeat-a-string
博客:http://singsing.io/blog/fcc/basic-repeat-a-string-repeat-a-string/

思路一:

  • 我利用 Array(num) 去创建一个数组,该数组中有 num 项
  • Array.fill() 去填充字符串
  • Array.join() 去拼接
  • 判断 num 是否小于 0,是的话直接返回空串,注意不能判断是否为真,因为 Number => Boolean 中只有 +0, -0false
function repeat(str, num) {
  if (num < 0) return ''
  return Array(num).fill(str).join('')
}

repeat("abc", 3);

其实嘛,看了博客知道另外一种解法,感觉是我对 Array.join() 不熟悉的原因。
Array.join() 把数组的各项用分隔符隔开,拼接成字符串,不传参的话,默认是用逗号隔开。

  • 如果是一个元素都为空的数组
  • 这个数组又用某个字符串分隔开
  • 是不是就得到一个重复多次的字符串
function repeat(str, num) {
  if (num < 0) return ''
  return Array(num + 1).join(str) // 注意:num + 1
}

repeat("abc", 3);

思路二:直接用 String.repeat

str.repeat(count):构造并返回一个新字符串,该字符串为指定数量的字符串的副本。

  • count: [0, 正无穷],为 0 时,返回一个空串,非整数时,向下取整。
function repeat(str, num) {
  if (num < 0) return ''
  return str.repeat(num)
}

const repeat = (str, num) => num > 0 ? str.repeat(num) : ''

repeat("abc", 3);

@tiu5
Copy link
Owner Author

tiu5 commented May 24, 2019

截断字符串 (Truncate a string)

题目:https://www.freecodecamp.cn/challenges/truncate-a-string
博客:http://singsing.io/blog/fcc/basic-truncate-a-string/

题目要求:

  • 如果字符串的长度比指定的参数num长,则把多余的部分用...来表示。
  • 如果指定的参数num小于或等于3,则添加的三个点号不会计入字符串的长度。
  • 插入到字符串尾部的三个点号也会计入字符串的长度。

思路:
分不同情况,进行字符串截取和拼接

function truncate(str, num) {
  // num 小于等于3时
  if (num < 4) {
    return str.slice(0, num) + '...';
  }
  // num 大于字符串长度时
  if (num >= str.length) return str;
  return str.slice(0, num - 3) + '...';
}

truncate("A-tisket a-tasket A green and yellow basket", 11);

使用三元运算符:a ? b : c

function truncate(str, num) {
  if (num < str.length) {
    return str.slice(0, num > 3 ? num - 3 : num) + '...'
  }
  return str
}

truncate("A-tisket a-tasket A green and yellow basket", 11)

其中 slice 也可以换成 substr, substring

@tiu5
Copy link
Owner Author

tiu5 commented May 24, 2019

猴子吃香蕉, 分割数组 (Chunky Monkey)

题目:https://www.freecodecamp.cn/challenges/chunky-monkey
博客:http://singsing.io/blog/fcc/basic-chunky-monkey/

题目要求:

  • 把一个数组arr按照指定的数组大小size分割成若干个数组块。
  • chunk([1,2,3,4,5],2)=[[1,2],[3,4],[5]];

解题思路:

  • 我们需要分割数组,那么我们看一下数组有哪些方法可以分割 console.log(Array.prototype) 找到
    • slice()
    • splice()
  • 分割完后,要放进数组,那么要用到:
    • push()
    • concat()
  • 那分割的过程呢,要用循环,因为不用一个个遍历,所以用的是 while
// 因为 splice() 会改变原数组的长度,所以可以直接判断数组长度
function chunk(arr, size) {
 var a = []
 while(arr.length) {
   a.push(arr.splice(0, size))
 }
 return a
}

chunk(["a", "b", "c", "d"], 2);

// 因为 slice() 不会修改原数组长度,所以用变量 i 去计数
function chunk(arr, size) {
 var a = []
 var i = 0
 while(i < arr.length) {
   a.push(arr.slice(i, i + size))
   i += size
 }
 return a
}

chunk(["a", "b", "c", "d"], 2);

// 然后 push 和 concat 的区别就是返回值
// push 返回的是 arr.length
// concat 返回的是 一个新数组

@tiu5
Copy link
Owner Author

tiu5 commented May 24, 2019

截断数组 (Slasher Flick)

题目:https://www.freecodecamp.cn/challenges/slasher-flick
博客:http://singsing.io/blog/fcc/basic-slasher-flick/

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

大概意思就是:给你一个数组,和一个数字 n ,然后你返回这个数组从 0 开始删除掉 n 个元素的数组。

立马就可以想到:splice() , 换个思路想想,截取剩余部分的话,那可以有 slice

  • 直接删掉数组的一部分 splice
// splice 解法
function slasher(arr, howMany) {
  // 请把你的代码写在这里
  arr.splice(0, howMany)
  return arr
}

function slasher(arr, howMany) {
  // 去掉多余的 arr
  return arr.splice(0, howMany) && arr
}

slasher([1, 2, 3], 2);
  • 截取剩余部分的 slice
function slasher(arr, howMany) {
  return arr.slice(howMany)
}

slasher([1, 2, 3], 2);
  • 当然你也可以用 shift 循环 n 次,这样也可以从 0 开始删除部分数组
function slasher(arr, howMany) {
  for (let i = 0; i < howMany; i++) {
    arr.shift()
  }
  return arr
}

slasher([1, 2, 3], 2);

@tiu5
Copy link
Owner Author

tiu5 commented May 25, 2019

比较字符串 (Mutations)

题目:https://www.freecodecamp.cn/challenges/mutations
参考博客:http://singsing.io/blog/fcc/basic-mutations/

如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回 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"]);

@tiu5
Copy link
Owner Author

tiu5 commented May 25, 2019

过滤数组假值 (Falsy Bouncer)

题目:https://www.freecodecamp.cn/challenges/falsy-bouncer
参考博客:http://singsing.io/blog/fcc/basic-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)

@tiu5
Copy link
Owner Author

tiu5 commented May 31, 2019

摧毁数组 (Seek and Destroy)

题目:https://www.freecodecamp.cn/challenges/seek-and-destroy
参考博客:http://singsing.io/blog/fcc/basic-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);

@tiu5
Copy link
Owner Author

tiu5 commented May 31, 2019

数组排序并找出元素索引 (Where Do I belong)

题目:https://www.freecodecamp.cn/challenges/where-do-i-belong
参考博客:http://singsing.io/blog/fcc/basic-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);

@tiu5
Copy link
Owner Author

tiu5 commented May 31, 2019

凯撒密码 (Caesars Cipher)

题目:https://www.freecodecamp.cn/challenges/caesars-cipher
参考博客:http://singsing.io/blog/fcc/basic-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");  // 你可以修改这一行来测试你的代码

@tiu5
Copy link
Owner Author

tiu5 commented Jun 1, 2019

给定范围内的数字总和 (Sum All Numbers in a Range)

题目:https://www.freecodecamp.cn/challenges/sum-all-numbers-in-a-range
参考博客:http://singsing.io/blog/fcc/intermediate-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);
}

@tiu5
Copy link
Owner Author

tiu5 commented Jun 1, 2019

比较两数组差异 (Diff Two Arrays)

题目:https://www.freecodecamp.cn/challenges/diff-two-arrays
参考博客:http://singsing.io/blog/fcc/intermediate-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]);

@tiu5
Copy link
Owner Author

tiu5 commented Jun 2, 2019

找出对象包含的特定键值对 (Where art thou)

题目:https://www.freecodecamp.cn/challenges/where-art-thou
参考博客:http://singsing.io/blog/fcc/intermediate-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" });

@tiu5
Copy link
Owner Author

tiu5 commented Jun 2, 2019

句中查找替换 (Search and Replace)

题目:https://www.freecodecamp.cn/challenges/search-and-replace
参考博客:http://singsing.io/blog/fcc/intermediate-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");

@tiu5
Copy link
Owner Author

tiu5 commented Jun 2, 2019

DNA 配对 (DNA Pairing)

题目:https://www.freecodecamp.cn/challenges/dna-pairing
参考博客:http://singsing.io/blog/fcc/intermediate-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");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant