FreeCodeCamp 算法题 3

比较字符串 (Mutations)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/ba…

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

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/ba…

删除数组中的所有假值。

思路: 遍历数组的元素,判断是否为真,为真的话放进一个数组内,最后返回该数组。

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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/ba…

// 初次解法
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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/ba…

题意: 一个数组,一个数字,然后这个数字在这个数组中,按小到大排序,它的下标应该是多少。

解法一:

  • 把数字添加到数组中 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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/ba…

题意: 给你一个大写字母的字符串,然后你把字符串的每一个字母向右移动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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/in…

题意:给一个数组,然后返回给定范围的数字总和。

例如:[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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/in…

题意:比较两个数组,然后返回一个新数组,该数组的元素为两个给定数组中所有独有的数组元素。换言之,返回两个数组的差异。

按照数学上集合来讲就是,两个集合并集减去它们的交集。

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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/in…

题意:

  • 给你一个对象数组,还有一个对象
  • 数组里的对象都包含第二个参数里的对象,还有键值相等
  • 返回一个过滤后的数组
// 首先返回的是数组,那么用 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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/in…

题意:

  • 使用给定的参数对句子执行一次查找和替换,然后返回新句子。
  • 第一个参数是将要对其执行查找和替换的句子。
  • 第二个参数是将被替换掉的单词(替换前的单词)。
  • 第三个参数用于替换第二个参数(替换后的单词)。
  • 注意:替换时保持原单词的大小写。例如,如果你想用单词 "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)

题目:www.freecodecamp.cn/challenges/…

参考博客:singsing.io/blog/fcc/in…

题目意思就是:给你一段残缺的碱基,返回一段碱基对,碱基对有: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");
复制代码

猜你喜欢

转载自blog.csdn.net/weixin_33724570/article/details/91368633
今日推荐