• FreeCodeCamp( FCC)前端工程师 基础算法练习 分析与解答


    FreeCodeCamp 前端工程师 基础算法练习 全解 详解

    本人属于很水的前端程序员中的一员,若文中有误,敬请指正! 为了提升自己,同时看到基础的还能应付,故而试之分享之!本文纯属于原创,转载请联系 wusuai1995@qq.com!

    // 第一章 反转字符串

    实现思路

    先将字符串切分成数组 String.prototype.split('') 这里括号中的 '' 必要 否则切分无效  类似的用法还有 String.prototype.join('')

    然后将该数组 Array.prototype.reverse() 返回翻转后的数组 

    然后 Array.prototype.join('') 重新拼接数组并返回修改后的新的字符串

    function reverseString(str) {
      return str.split('').reverse().join('');
    }
    
    reverseString("hello");

    //第二章 判断是否回文字符串

    实现思路: 阶乘 !n 

    递归调用自身直到 num === 0 再闭包往上返回每一层的结果

    在 debugger 模式下(上帝视角)  我们可以清晰看到函数执行过程  JavaScript 解析器开始执行函数 在 call stack 中 压入当前 factorialize  函数及其 local scope 数据

    直到 num === 0 时 函数开始 retrun value 层层返回 并在调用函数完成之后从 call stack 中清除当前调用函数 并返回上次调用反正结果给当前 栈顶的 factorialize 使用

    function factorialize(num) {
    // 在非严格模式下可以使用 arguments.callee 调用自身 
    // TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
     // return num === 0 ? 1 : arguments.callee(num-1) * num;
     debugger; //(博主的 debugger 因为 freeCodeCamp 的 setTimeOut 进入了无限循环!!! WTF!)
    return num === 0 ? 1 : factorialize(num - 1) * num; } factorialize(5); //120

     
    // 第三章 检查字符串是否是回文字符串

    实现思路:

    先处理原字符串 去掉非字符之外的内容 String.prototype.replace()

    然后讲字符串全部转换成小写字符方便比较 String.prototype.toLowerCase()

    在用变量 str1 来缓存翻转之后的字符串 思路与第一章一致 

    最后在 return str === str1 即可

    function palindrome(str) {
      str = str.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
      var str1 = str.split('').reverse().join('');
      return str === str1;
    }
    
    palindrome("eye");

    // 第四章 找到句子中最长的字符串

    实现思路:

    先将函数参数 str 根据 /s/ 切分成数组 strArr

    声明一个哨兵变量 strLen = 0 

    再使用 Array.prototype.forEach() 判断当前 item 的长度是否大于变量 strLen 如果大于 strLen 则对 strLen 重新赋值

    最后在 forEach 循环完成之后 return strLen

    function findLongestWord(str) {
      var strArr = str.split(/s/);
      var strLen = 0;
      strArr.forEach(function(item){
        if (item.length > strLen) {
          strLen = item.length;
        }
      });
      return strLen;
    }
    
    findLongestWord("The quick brown fox jumped over the lazy dog");

    // 第五章 将句中每个单词首字母大写

    实现思路: 其实这个在很多支持组件 (component) 的库中都有实现 比如:vue angualr react 错了 汗  他们实现的是 属性驼峰 和 a-b-c 此类组件名转驼峰

    通上一章 第一步先将函数参数 str 根据 /s/ 切分成数组 strArr 随后情况参数 str = ''

    然后遍历 strArr 中每一项 item.substr(0, 1).toUpperCase() 将每一项的第一个字母取出来并大写 String.prototype.substr() 再调用 String.prototype.toUpperCase()

    然后将每一项 字符串中除去第一个后 的字符并全部转成小写  item.slice(1).toLowerCase() String.prototype.slice()

    如果当前项的索引不等于最后一项则 str += item + ' ' 否则 str += item

    function titleCase(str) {
      var strArr = str.split(/s/);
      str = '';
      strArr.forEach(function(item, idx) {
      // 这一步用这正则来实现应该更加舒心 有时间在去玩正则吧 item
    = item.substr(0, 1).toUpperCase() + item.slice(1).toLowerCase(); idx !== strArr.length -1 && (str += item + ' ') || (str += item); }); return str; } titleCase("I'm a little tea pot");

    // 第六章 返回传入数组中的最大数字

    实现思路: 思路与第四章基本一致

    function largestOfFour(arr) {
      // 首先传入的是一个二维数组
      // 其次比较传入数组中每项数组的最大值然后push到新数组中
      // 返回新数组
      var maxArr = [];
      arr.forEach(function(arr) {
        // 局部变量或者称之为哨兵变量
        var maxNum = 0;
        arr.forEach(function(num){
          if (num > maxNum) {
            maxNum = num;
          }
        });
        // 内部arr forEach完成之后 maxNum 一定会是数组中最大值
        maxArr.push(maxNum);
      });
      // You can do this!
      return maxArr;
    }
    
    largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

    // 第七章 检查一个字符串(str)是否以指定的字符串(target)结尾。
    实现思路: 在代码中
    实际上我认为我的写法有点复查 如果各位看官有更好更简单明了的写法还请留言。

    function confirmEnding(str, target) {
      // 首先判断 str 是句子还是单词
      // 我们简单根据 是否有 空格 来判断
      var isSentence = /s/.test(str);
      // 然后判断 target 是字母还是单词
      // 我们简单根据 target.length 来判断 如果 length > 1 则认为是单词
      var isWord = target.length !== 1;
      
      var strArr = [], lastChar = '';
      
      // 如果是句子 则 target 应该是个单词
      // 否则判断无效 或者 return null 或者 false
      // 如果 lastChar.length === targetLenth 我们则直接判断 lastChar===target
      // 否则 我们截取 lastChar 指定的 target.length 再判断
      if (isSentence && isWord) {
        strArr = str.split(/s/);
        lastChar = strArr.slice(-1)[0];
        
        // 根据 target 长度来取 lastChar 的长度
        if (lastChar.length !== target.length) {
          lastChar = lastChar.slice(target.length);
        }
      } else {
        // lastChar = str.substr(str.length-1, str.length);
        lastChar = str.slice(str.length-1);
      }
      // "Never give up and good luck will find you."
      // -- Falcor
      
      return lastChar === target;
    }
    
    confirmEnding("Bastian", "n");

    // 第八章 重复一个指定的字符串 num次,如果num是一个负数则返回一个空字符串。

    function repeat(str, num) {
      var oldStr = str;
      str = '';
      // 肯定需要循环当前的 num 
      if (num > 0) {
        for(var i=0; i<num; i++) {
          str += oldStr;
        }
      }
      // repeat after me
      return str;
    }
    
    repeat("abc", 3);

    // 第八章 如果字符串的长度比指定的参数num长,则把多余的部分用...来表示。

    function truncate(str, num) {
      // Clear out that junk in your trunk
      // 首先判断给出的 num 是否大于 3  
      // 其次判断给出的 num 是否大于 str.length 如果大于则返回原str
      if (num > 3) {
        if (num >= str.length) {
          return str;
        }
        str = str.replace(str.slice(num - 3), '...');
      } else {
        str = str.replace(str.slice(num), '...');
      }
      return str;
    }
    
    truncate("A-tisket a-tasket A green and yellow basket", 11);

    // 第九章 把一个数组arr按照指定的数组大小size分割成若干个数组块。

    function chunk(arr, size) {
      // 定义将返回的新数组
      var newArr = [];
      // 求出新数组 根据 arr.length / size 的长度
      // Math.ceil() 向上取整
      var newArrLen = size < arr.length ? Math.ceil(arr.length / size) : 0;
      
      // 判断 newArrLen 是否有效
      if (newArrLen) {
        // 循环 Array.prototype.slice() 到新数组中
        for (var i=0; i<newArrLen; i++) {
          newArr.push(arr.slice(i * size, (i+1) * size));
        }
      } else {
        return arr;
      }
      // Break it up.
      return newArr;
    }
    
    chunk(["a", "b", "c", "d"], 2);

    // 第九章 返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始。

    function slasher(arr, howMany) {
      // it doesn't always pay to be first
      return arr.slice(howMany);
    }
    
    slasher([1, 2, 3], 2);

    // 第十章 如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true。

    function mutation(arr) {
      // 因为测试中所有的结果都有两项 
      // 所以不考虑 arr存在大于两项的情况
      // 首先我们要分割 arr[0] 与 arr[1] 全部转换成小写 再使用 String.protottype.indexOf() 判断
      // 假设 isSame 为 true
      var str2Arr = arr[1].toLowerCase().split('');
      var isSame = true;
      // 遍历数组 str2Arr 
      // 如果循环中检测到 当前字段不存在则 isSame = false
      for (var i=0, l=str2Arr.length; i<l; i++) {
        var str = str2Arr[i];
        if (arr[0].toLowerCase().indexOf(str) < 0) {
          isSame = false;
          break;
        }
      }
      return isSame;
    }
    
    mutation(["hello", "hey"]);

    // 第十一章 删除数组中的所有假值

    function bouncer(arr) {
      // Don't show a false ID to this bouncer.
      // 使用 Array.prototype.filter()  自动过滤掉 boolean(item) 为假的值
      return arr.filter(function(item){
        return item;
      });
    }
    
    bouncer([7, "ate", "", false, 9]);

    // 第十二章 实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。

    function destroyer(arr) {
      // 参数数组
      var args;
      // Remove all the values
      if (arguments.length > 1) {
        // Function.prototype.call() or Function.prototype.apply()
        args = Array.prototype.slice.call(arguments, 1, arguments.length);
      } else {
        return arr;
      }
      return arr.filter(function(item) {
        // 只有在args数组中的参数不存在arr中时才返回 Array.prototype.indexOf()
        // 这样就过滤掉了那些待摧毁的值
        return args.indexOf(item) < 0;
      });
    }
    
    destroyer([1, 2, 3, 1, 2, 3], 2, 3);

    // 第十三章 先给数组排序,然后找到指定的值在数组的位置,最后返回位置对应的索引。

    function where(arr, num) {
      // Find my place in this sorted array.
      // 首先调用 Array.prototype.sort() 升序数组 传入参数 compareFn
      // 然后循环数组 插入 num 返回当时的插入位置的索引 插入用 Array.prototype.splice()
      arr.sort(function(a, b){
        return a>b ? 1 : -1;
      });
      
      for (var i=0,l=arr.length; i<l; i++) {
        var previous = i !== 0 ? arr[i-1] : 0;
        var current = arr[i];
        // 如果 num 大于 上一个值 小于 当前值
        // 则就在该 i-1 处插入 num
        // 如果相等 就在 相等的值后面插入 num
        // 如果 num 一直大于数组中的每一项 那么 num 就应该数组的最后一项插入
        if (((num > previous && num < current) || num === current) || (i === l-1 && num > current)) {
          if (i === l-1 && num > current) {
            arr.splice(l, 0, num);
            num = l;
          } else {
            arr.splice(i, 0, num);
            num = i;
          }
          break;
        }
        
      }
      return num;
    }
    
    where([40, 60], 50);

    写到这里真的很累了,不写了。留下一题?no! 那还是做了吧!

    // 第十四章  密码中的字母会按照指定的数量来做移位。

    // 这个赶时间 回去弄 下吃饭  身体重要 朋友!

    function rot13(str) { // LBH QVQ VG!
      // 仅仅显示出来方便查看
      var wordsArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      
      // 首先将字符串切分成数组
      var strArr = str.toUpperCase().split(''), offsetNum = 13;
      str = '';
      
      // 参与计算的字符串应该都是大写 String.prototype.toUpperCase()
      // 所以正确的 charCode  A.charCodeAt("") <= str.charCodeAt(0) <= "Z".charCodeAt(0) - 13
      var maxCharCode = 'Z'.charCodeAt(0) - offsetNum, charCode = null, offsetCharCode = null;
      
      for (var i = 0, l = strArr.length; i<l; i++) {
        //  如果是 英语字符 则执行 转换操作
        if (/[a-zA-Z]/.test(strArr[i])) {
          // 得到当前项的 charCode
          charCode = strArr[i].charCodeAt(0);
          // 如果当前的 charCode > maxCharCode 则将算法改为 减去位移数字 否则还是照常加上 位移数字
          offsetCharCode = charCode > maxCharCode ? charCode - offsetNum  : charCode + offsetNum;
          // 得到当前字符 偏移 13 位的 字符编码后 在调用 String.fromCharCode() 方法返回对应字符串
          strArr[i] = String.fromCharCode(offsetCharCode);
        }
      }
      
      // Array.prototype.join() 得到修改后的字符串再返回
      str = strArr.join('');
    
      return str;
    }
    
    // Change the inputs below to test
    rot13("SERR PBQR PNZC");


    刚开始写很细心,很用心。写到后面时间越花越多,有点顾此失彼。故只显示代码,不口水话什么思路了。

    总结

    1. 这些真的很基础,基础到只要熟悉API就好!

    2. 当然,由于是 JavaScript 的缘故,多多少少会有点小坑在!(毕竟我是菜鸟)

    3.上面所有答案纯属个人见解,如果你有更好的解法,欢迎留言共同探讨!

    4. 博客纯属个人原创,转载请联系本人! wusuai1995@qq.com!

  • 相关阅读:
    git 常用命令
    centos 7 mini 安装
    python打印杨辉三角
    python 求100内的素数/质数
    字符串与bytes
    format
    Python字符串格式化
    数据结构
    ARM工作模式
    C语言实现字符串逆序输出
  • 原文地址:https://www.cnblogs.com/givingwu/p/6838201.html
Copyright © 2020-2023  润新知