Day07 JavaScript(Algorithm)

Free Code Camp的JavaScript算法

翻转字符串(Reverse a String

实现:先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串。

function reverseString(str) {
  newStr = str.split("");    //将字符串分割为单个字符,并且每个字符作均作为数组的一个元素
  newStrReverse = newStr.reverse();      //翻转数组元素顺序
  strUnordered = newStrReverse.join("");    //连接数组的每个元素,没有分隔符,组成一个字符串
  return strUnordered;
}
reverseString("hello");

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

使用n表示一个整数,阶乘代表所有小于或等于n的整数的乘积,阶乘写成n!
n! = 1 * 2 * 3 * ... * (n-1) * n

function factorialize(num) {
  if(num <= 1) {
    return 1;            //处理num为0和1的情况,0!等于1。
  } else {
     return num * factorialize(num - 1);     //递归调用factorialize()函数
  }
}
factorialize(5);

字符串回文(Check for Palindromes

01、捣鼓了一下午,终于把回文数弄出来了。之前一直卡在怎么匹配出不带标点和空白的字符串上,finally还是找到了,就是个枚举的正则表达式...顺带看了点正则表达式的知识,明、后天好好看看正则表达式的内容。
02、就是找到了效率高一点的判断回文数的方法

  • 如果一个字符串忽略标点符号、大小写和空格,顺着读和倒着读相同,则这个字符串是回文palindrome
  • 需要去掉字符串的标点符号和空格,并且将字符串全部转化为小写(或大写)来验证字符串是否回文。
function palindrome(str) {
    //匹配所有标点符号(英文的),并且匹配所有空白符(/s)
    var expression = /[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|<|\.|>|\/|\?|\s]+/g; 

    //使用replace()方法将所有标点和空白替换为空,相当于将所有文本字符连接在一起;并且将所有字符转化为小写(不会改变原字符串)
    var allChar = str.replace(expression, "").toLowerCase(); 

    //将字符串分割为单子字符数组,反转数组,再合并数组成一个字符串
    var allLowerChar = allChar.split("").reverse().join("");  、

    //比较原字符串与反转后字符串是否相同,相同返回true,不同返回false
    if(allLowerChar === allChar) {
      return true;
    } else {
      return false;
    }
}
palindrome("woca");     //调用

注:使用正则表达式expression = /[\~|\|!|@|#|$|%|^|&|*|(|)|-|_|+|=|||\|[|]|{|}|;|:|"|'|,|<|.|>|/|?]+/g`可以匹配字符串中的所有标点符号。

去掉开头的\ |,用于匹配空格,使用后面的\s来匹配所有的空白符。

  • 使用上述方法判断回文字符串,方便简单,但是效率不高,字符串的split()reverse()join()需要很多额外的操作。
  • 回文字符串的特点:第一个字符和最后一个字符相同,第二个字符和倒数第二个字符相同...(回文字符串从左向右或是从右向左读都相同

  • 递归方法判断--推荐方法
    递归的作用在于不断减小所处理问题的规模,直到可以解决为止。
    回文字符串问题:可以每次比较端部的字符,如果相同则去掉,再次比较端部字符;如果不同则返回false。直到只剩中间的字符、或不剩下字符时,返回true
function isPalindrome(str) {
    var expression = /[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|<|\.|>|\/|\?|\s]*/g; 
    var allChar = str.replace(expression, "").toLowerCase(); 
  
    for(var i = 0, j = allChar.length - 1; i < j; i++, j--) {
      if(allChar.charAt(i) !== allChar.charAt(j)) {
        return false;
      }       //.charAt(i)返回字符串索引为i位置的字符
    } 
    return true;    //如果执行完循环没有退出,`str`为回文字符串
}
isPalindrome("ooaaoo");

找到句子中最长的单词(Find the longest world in a string

  • 找到提供的英文句子(字符串)中最长的单词,并计算它的长度;函数返回值是一个数组。
  • 自己的思路:将整个字符串以空格分割,构建以每个单词为元素的数组(字符串的.split( )方法);在根据单词的长度排序整个数组,最长的字符串在数组的端部。
function findLongestWord(str) {
    var strArray = str.split(" ");   //转化为以单词为元素的数组,以空格为分隔符
    var strSort = strArray.sort(function(a, b) {
      return b.length - a.length;      //递减排序(如果a-b则是递增排序),看看`sort(a, b)`的文档
   });
  
    var lenMax = strSort[0].length;
  
    return lenMax;
}
findLongestWord("The quick brown fox jumped over the lazy dog");
  • 可能存在的问题
    1、没有去掉句子中的标点符号
    2、当一个句子中有多个单词长度相同时如何处理
function titleCase(str) {
    return str.toLowerCase().split(' ').map(function(word) {
      return word.charAt(0).toUpperCase() + word.slice(1);
    }).join(' ');     //先将字符串全部转化为小写,再以空格分割为以单词为元素的数组,然后将每个单词的首字母大写,最后以空格连接每个元素,重新组合为字符串。
}
titleCase("I'm a little tea pot");

返回数组中的最大值(Return Largest Numbers in Arrays

  • 数组的元素是数值数组,分别找到每个子数组的最大值,将其串联起来形成一个新的数组。
  • 思路:写一个函数largeOne(arr1),其功能是找到一个数组中的最大值,并将其返回;再写另一个函数,分别将每个数组作为参数传入largeOne,最后将得到的值添加到一个新的数组中.push()方法。
//返回一个数组中的最大值
function largeOne(arr) {
    var max = 0;
    for(var i = 0; i < arr.length; i++) {
      if(arr[i] > max) {
        max = arr[i];
      }
    }
    return max;
}
//分别迭代每个数组,把最大值添加到新的数组中
function largestOfFour(arr) {
    var newArr = [];
    for(var i = 0; i < arr.length; i++) {
      newArr.push(largeOne(arr[i]));       //选出最大的值并添加到新的数组中
    }
    return newArr;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

检查一个字符串的结尾(Confirm the Ending

  • 检查一个字符串str是否以指定的字符串target结尾。
  • 思路:利用.slice()方法,根据target的长度,提取出str的末尾部分,将之与target比较,如果相同返回true
function confirmEnding(str, target) {
    if(str.slice(str.length - target.length, str.length) === target) {   //忽略slice()的第二个参数,默认提取到字符串的末尾
      return true;
    } else {
    return false;
    }
}
confirmEnding("Bastian", "n");
  • 使用.substr()方法,类似于slice()方法。
function confirmEnding(str, target) {
    if(str.substr(str.length - target.length) === target) {
      return true;
    } else {
      return false;
    }
}
confirmEnding("Bastian", "n");

重复一个字符串(Repeat a String

  • 重复一个字符串num次,如果num为负,则返回一个空字符串。
  • 思路:采用+操作符,可以连接+左右两边的字符串,之间没有空格。使用一个for循环实现叠加。
  function repeat(str, num) {
    var newStr = "";
    if(num <= 0) {
      return "";
    } else {
        for(var i = 0; i < num; i++) {
          newStr += str;
        }
      }  
    return newStr;
}
repeat("abc", 3);

截断字符串(Truncate a String

  • 问题描述:如果字符串长度大于指定的参数num,则将多余的部分用...表示。(插入带字符串尾部的三个.也会计入字符串长度,但是如果参数num <= 3,则添加的三个.不会计入字符串长度
  • 思路:用一个if判断字符串长度是否大于num,如果false则返回原字符串;如果true,在继续判断num与3的关系,大于3时,.计入字符串的长度;小于3时,.不计入字符串长度。
function truncate(str, num) {
    //如果字符串长度大于指定参数num
    if(str.length > num) {
      //如果参数num > 3
      if(num > 3) {
        return str.slice(0, num - 3) + "...";    //-3是三个.会计入字符串的长度
      } else {
        return str.slice(0, num) + "...";      //三个.不计入字符串长度
      }
    } else {
      return str;
    }
}
truncate("A-tisket a-tasket A green and yellow basket", 11);

将数组分割为若干块(Chunky Monkey

  • 把数组arr按照指定的size分割成若干个数组块,例如chunk([1,2,3,4],2)=[[1,2],[3,4]];chunk([1,2,3,4,5],2)=[[1,2],[3,4],[5]];
  • 思路:先分离arr.length < sizesize <= 0的情况,再利用.slice().push()操作,利用for循环迭代提取arr的数组块,并添加到新数组中。
function chunk(arr, size) {
  var newStr = [];
  var temp = [];
  var len = arr.length;
  
  if(len < size || size <= 0) {
    return arr;
    } else {
    for(var i = 0; i < len; i += size) {
      temp = arr.slice(i, i + size);
      newStr.push(temp);
      }
    return newStr;
    }
}
chunk(["a", "b", "c", "d"], 2);

注意:参考资料

Slasher Flick

  • 返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始。
  • 思路:直接采用数组的.slice()方法获取元素组的后n个元素,赋值给新的空数组。
function slasher(arr, howMany) {
    if(arr.length < howMany) {
      return [];
    } else {
      var newArr = arr.slice(-(arr.length-howMany));  //采用负索引,访问数组的倒数元素
      return newArr;
    }
  }
slasher([1, 2, 3], 2);

注:采用.splice()方法,可以删除原数组中的前n个元素。.splice()会直接修改原数组。

function slasher(arr, howMany) {
    if(arr.length < howMany) {
      return [];
    } else {
      arr.splice(0, howMany);   //参考MDNjs的文档
      return arr;
    }
}
slasher([1, 2, 3], 2);

Mutations

  • 如果数组第一个字符串元素包含了第二个字符串元素的所有字符(忽略大小写),函数返回true,否则返回false
  • 采用[indexOf()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)方法,返回指定值在字符串对象中首次出现的位置。如果不存在,则返回-1`。
function mutation(arr) {
    var str1 = arr[0].toLowerCase();
    var str2 = arr[1].toLowerCase();
    var len = str2.length;
  
    //遍历str2的每个字符,如果有一个字符不在str1中,则返回false,如果全部通过,则返回true
    for(var i = 0; i < len; i++){
      if(str1.indexOf(str2[i]) === -1) {
        return false;
      }
    }
    return true;
}
mutation(["hello", "hey"]);

Falsy Bouncer

  • 删除数组中的所有假值(falsenull、0、undefinedNaN)。
  • 思路:采用.filter()方法,过滤掉返回值为false的数组元素,不会改变原数组。参考Boolean Object
function isFake(element) {
   if(element) {
     return true;
   } else {
     return false;
   }
}
function bouncer(arr) {
   var newArr = arr.filter(isFake);  
   return newArr;        //filter()方法不会改变原数组
}
bouncer([7, "ate", "", false, 9]);

Seek and Destroy

  • 实现一个摧毁destroy()函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。
  • 思路:使用arguments.length获得传入的参数个数,去掉第一个,剩下的为需要摧毁的值。使用.includes()方法作为过滤函数,判断第一个数组参数中的每个元素是否出现在后面的参数中,出现则过滤掉;其余分别.push()到新的孔数组中。
function destroyer(arr) {
    var tempArr = [];
    var newArr = [];
    var len = arguments.length;
    //构建其余参数数组
    for(var i = 1; i < len; i++) {
      tempArr.push(arguments[i]);       //使用arguments.length可以获得传入的参数数量
    }
  
    //遍历第一个数组参数,如果数组元素在tempArr中,则淘汰;如果不在,则增加到newArr中,最后得到淘汰后的数组
    for(var j = 0; j < arguments[0].length; j++) {
      if(!tempArr.includes(arguments[0][j])) {
         newArr.push(arguments[0][j]);
         }
    }
    return newArr;               //使用arguments.length可以获得传入的参数个数
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);

注:.filter()方法没有想出怎么实现。。。

Where Do I Belong

  • 先给数组排序,然后找到指定值在数组中的位置,最后返回位置的索引。
  • 野路子:先将元素添加到数组后面,再对数组排序,然后遍历数组,找到插入的元素,最后循环变量i即是索引。
function where(arr, num) {
  // Find my place in this sorted array.
    arr.push(num);
    arr.sort(function(a, b) {
      return a - b;
    });
  
    for(var i = 0; i < arr.length; i++) {
      if(arr[i] === num) {
        return i;   //返回第一个值得索引
      }
    }
}
where([5, 3, 20, 3], 5);

Caesars Cipher

  • Caesars Cipher又称凯撒码(位移码),密码中的字母按照指定的位数来做位移,密码中的字母按照指定的数量来做位移。ROT13密码:字母向后移动13个位置,A->NB->ON->A...,ROT13(ROT13(x)) == x
  • 思路:先将字符串.split("")方法,将字符串中的每个字符分给为一个数组元素,然后遍历数组元素。如果Unicode码在[97, 122]之间(只有大写字母),则按照算法向后推算;如果不在,则保持原状(空格和标点不处理)。
  • 方法:当Unicode码在[65-77]之间时,直接每个加上13然后重新赋值;在[78-90]之间时,每个加上13,再减去26,最后赋值。
function rot13(str) { // LBH QVQ VG!
    var newArr = str.split("");
    var arr = [];
  
    //大写字母的Unicode码从65到90
    //如果在78-90之间,Unicode值减去13,;在65-77之间,Unicode值加上13
    //最后转化为字符。
    for(var i = 0; i < newArr.length; i++) {
      if(newArr[i].charCodeAt() <= 90 && newArr[i].charCodeAt() >= 78) {
        arr[i] = String.fromCharCode(newArr[i].charCodeAt() - 13);
      } else if(newArr[i].charCodeAt() <= 77 && newArr[i].charCodeAt() >= 65) {
        arr[i] = String.fromCharCode(newArr[i].charCodeAt() + 13);
      } else {
        arr[i] = newArr[i];      //不在65-90之间的不处理,略去空格和标点
      }
    } 
    return arr.join("");      //组合回字符串
}
// Change the inputs below to test
rot13("SERR PBQR PNZC");

居然做完了

哈哈,花了也不知道几天的空余时间,终于刷完了这点儿题,其中大部分都是自己完成,有些参考了网上的代码,不过都是亲手敲出来的码,哈哈哈哈,自己居然能想出来!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容