FCC上的初级算法题
核心提示:FCC的算法题一共16道。跟之前简单到令人发指的基础题目相比,难度是上了一个台阶。主要涉及初步的字符串,数组等运算。仍然属于基础的基础,官方网站给出的建议完成时间为50小时,超出了之前所有非项目题目的一倍还多。由此可见它的分量。现将自己的解题过程做个记录,有兴趣的人可以一起来试试。
2017.1更新:
博客门可罗雀,阅读数最高的几篇文章竟无一例外全是FCC的答案。聊天室里最多的话题是“我要源码”。拿来主义确实很好,但我希望写自己的代码。如果有一两个人能贬低这些代码,提出更好的方案,那写这些笔记的目的就达到了。
现在回看最初的代码,觉得当初自己真是不折不扣的初学者。现在呢?依然如旧。我希望在追梦的路上,永远当一个初学者。
在做项目的时候,这些问题实际上很常见。所以出于升级思维,花一个小时重写大部分算法。原来的代码就不避丑了。
1.翻转字符串
先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串。
你的结果必须得是一个字符串
function reverseString(str) {
  return str;
}
reverseString("hello");
思路:
(1)字符串转数组用的是split方法,数组转字符串用join方法
split()方法通过把字符串分割成子字符串来把一个String对象分割成一个字符串数组。参数
当然,你也可以做一个循环把字符串一个个加回去
(2) 倒序重排数组用的是reverse方法
解法
var newStr='';
function reverseString(str) {
  var arr=str.split('');//把字符串分割为['h','e','l','l','o']
  arr.reverse();//倒序排列数组
  newStr=arr.join('');//把数组转为字符串
  return newStr;//别忘了返回。
}
reverseString("hello");
2017.1更新:
function reverseString(str) {
return str.split('').reverse().join('');
}
2.计算一个整数的阶乘
如果用字母n来代表一个整数,阶乘代表着所有小于或等于n的整数的乘积。
阶乘通常简写成 n!
例如: 5! = 1 * 2 * 3 * 4 * 5 = 120
function factorialize(num) {
  return num;
}
factorialize(5);
思路:用循环,*=做、所需要注意的只是循环起点。
function factorialize(num) {
  var i=1;
  var product=1;
  for(i=1;i<=num;i++){
    product*=i;
  }
  return product;
}
factorialize(5);
3.如果给定的字符串是回文,返回true,反之,返回false。
如果一个字符串忽略标点符号、大小写和空格,正着读和反着读一模一样,那么这个字符串就是palindrome(回文)。
注意你需要去掉字符串多余的标点符号和空格,然后把字符串转化成小写来验证此字符串是否为回文。
函数参数的值可以为"racecar","RaceCar"和"race CAR"。
function palindrome(str) {
  // Good luck!
  return true;
}
palindrome("eye");
思路,要转化字符串为无标点的字符串需要两个方法
(1)replace() 方法
用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。xxx。replace(正则表达式,'xxxx')
(2)转换小写——toLowerCase()
2017.1 追加:其实这是比较有价值的题目。
function palindrome(str) {
  // Good luck!
  var newStr= str.replace(/\W+/g,'');//匹配所有非单词的字符,替换为空字符串
  newStr= newStr.replace(/\_+/g,'');//匹配所有下划线,替换为空字符串
  newStr=newStr.toLowerCase();
  //转化字符串为小写
  var arr1= newStr.split('');
  var arr2=arr1.reverse();
  var newStr2=arr2.join('');
  //重构倒序的字符串
  if(newStr===newStr2){//比较1
    return true;
  }else{
   return false;
  }
}
一个优化的思路:
function palindrome(str) {
  // Good luck!
  str = str.replace(/[^A-Za-z0-9]/g,'').toLowerCase();
  for(var i=0;i<str.length/2;i++){
    if(str[i]!==str[str.length-i-1]){
      return false;
    }
  }
  return true;
}
还有更简单的思路
function palindrome(str) {
  // Good luck!
  var re = /[\W\s_]/gi;
  str = str.replace(re,"");
  return str.toLowerCase() === str.split("").reverse().join("").toLowerCase();
}
palindrome("eye");
4.找到提供的句子中最长的单词,并计算它的长度。
函数的返回值应该是一个数字。
这个没有用什么生疏的方法,split拆分字符串,然后循环判断最长的String.length;
function findLongestWord(str) {
  var arr=str.split(' ');
  var wordLength=0;
  for(i=0;i<arr.length;i++){
    if(arr[i].length>wordLength){
      wordLength=arr[i].length;
      LongestWord=arr[i];
    }
  }
  return wordLength;
}
findLongestWord("The quick brown fox jumped over the lazy dog");
2017.1追加:
function findLongestWord(str) {
var arr=str.split(' ');
arr=arr.map(function(item){
return item.length;
}).sort(function(a,b){
return b-a;
}); return arr[0];
}
思路会不会清晰点呢?
5.确保字符串的每个单词首字母都大写,其余部分小写。
像'the'和'of'这样的连接符同理。
思路,先用split拆分单词,在拆分单词的每个字母,首个字母设置大写,后面的全部设置小写。然后再组合成词,最后再组合为句子。
function titleCase(str) {
  var arr=str.split(' ');
  for(i=0;i<arr.length;i++){
    arr2=arr[i].split('');
    arr2[0]=arr2[0].toUpperCase();
    for(j=1;j<arr2.length;j++){
      arr2[j]=arr2[j].toLowerCase();
    }
    arr[i]=arr2.join('');
  }
  var newStr=arr.join(' ');
  return newStr;
}
2017.1追加:
思路是在map遍历中构造一个新的词组。
function titleCase(str) { var newStr=str.toLowerCase().split(' ').map(function(item){
return item[0].toString().toUpperCase()+item.slice(1);
}).join(' '); return newStr;
}
6.右边大数组中包含了4个小数组,分别找到每个小数组中的最大值,然后把它们串联起来,形成一个新数组。
function largestOfFour(arr) {
  // You can do this!
  return arr;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
提示:你可以用for循环来迭代数组,并通过arr[i]的方式来访问数组的每个元素。
思路,主要是用了数组排序的方法。
function largestOfFour(arr) {
  // You can do this!
  var newArr=[];
  for(i=0;i<arr.length;i++){
    arr[i].sort(function(a,b){
      return b-a;
    });
    newArr.push(arr[i][0]);
  }
    return newArr;
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
7.检查一个字符串(str)是否以指定的字符串(target)结尾。
如果是,返回true;如果不是,返回false。
思路:主要是用到了substr() 方法
substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。
var str="Hello world!"
document.write(`str.substr(3)`)
输出结果:
lo world!
根据这个方法,可以用String.length来截取想要的部分进行判断。
function confirmEnding(str, target) {
  if(str.substr(str.length-target.length)==target){
    return true;
  }else{
    return false;
  }
}
2017.1更新:
题目提示用substr方法,但是slice或许更好阅读一些
function confirmEnding(str, target) { if(str.slice(-target.length)==target){
return true;
}else{
return false;
}
}
8.重复一个指定的字符串 num次,如果num是一个负数则返回一个空字符串。
没什么可说的
function repeat(str, num) {
  // repeat after me
  var str0=str;
  if(num<=0){
    return '';
  }else{
    for(i=0;i<num-1;i++){
      str+=str0;
    }
    return str;
  }
}
2017.1更新:
function repeat(str, num) {
// repeat after me
var newStr='';
for(var i=1;i<=num;i++){
newStr+=str;
}
return newStr;
}
9.截断一个字符串!
如果字符串的长度比指定的参数num长,则把多余的部分用...来表示。
切记,插入到字符串尾部的三个点号也会计入字符串的长度。
但是,如果指定的参数num小于或等于3,则添加的三个点号不会计入字符串的长度。
function truncate(str, num) {
  // Clear out that junk in your trunk
  return str;
}
truncate("A-tisket a-tasket A green and yellow basket", 11);
思路:
slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。比如说:
var str="Hello happy world!"
document.write(str.slice(6,17))//输出"happy world"
function truncate(str, num) {
  // Clear out that junk in your trunk
  var newStr='';
  if(str.length>num){
    if(num<=3){
      newStr=str.slice(0,num)+'...';
    }else{
      newStr=str.slice(0,num-3)+'...';
    }
    return newStr;
  }else{
    return str;
  }
}
2017.1更新:
function truncate(str, num) {
var result='';
if(str.length<=num){
result=str;
}else{
result=num>3?str.slice(0,num-3)+'...':str.slice(0,num)+'...';
}
return result;
}
10.把一个数组arr按照指定的数组大小size分割成若干个数组块。
例如:chunk([1,2,3,4],2)=[[1,2],[3,4]];
chunk([1,2,3,4,5],2)=[[1,2],[3,4],[5]];
function chunk(arr, size) {
  // Break it up.
  return arr;
}
chunk(["a", "b", "c", "d"], 2);
如果不用slice做,要对情况做分类讨论:
function chunk(arr, size) {
  // Break it up.
  var newArr=[];
  var i=0;
  var tempArr=[];
  if(arr.length%size!==0){
    for(i=0;i<=arr.length;i++){
      if(tempArr.length==size){
          newArr.push(tempArr);
          tempArr=[];
        }
      if(i==arr.length){
        newArr.push(tempArr);
        break;
      }
      tempArr.push(arr[i]);
    }
  }else{
    for(i=0;i<=arr.length;i++){
        if(tempArr.length==size){
          newArr.push(tempArr);
          tempArr=[];
        }
        tempArr.push(arr[i]);
    }
  }
而slice方法可以这样实现:
function chunk(arr ,size) {
  var newarr=[];
  for(var i=0;i<arr.length;i+=size) {
    newarr.push(arr.slice(i,i+size));
  }
  return newarr;
}
chunk(["a", "b", "c", "d"], 2);
11.返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始。
function slasher(arr, howMany) {
  // it doesn't always pay to be first
  if(howMany===0){
    return arr;
  }
  arr=arr.splice(howMany,arr.length-1);
  return arr;
}
slasher([1, 2, 3], 2);
2017.1更新:
貌似这样就可以了
function slasher(arr, howMany) {
// it doesn't always pay to be first
return arr.slice(howMany);
}
12.如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true。
举例,["hello", "Hello"]应该返回true,因为在忽略大小写的情况下,第二个字符串的所有字符都可以在第一个字符串找到。
["hello", "hey"]应该返回false,因为字符串"hello"并不包含字符"y"。
["Alien", "line"]应该返回true,因为"line"中所有字符都可以在"Alien"找到。
var str="Hello world!"
document.write(str.indexOf("Hello") + "
")//0
document.write(str.indexOf("World") + "
")//-1
最直接的办法
function mutation(arr) {
  var a1=arr[0].toLowerCase();
  var a2=arr[1].toLowerCase();
  if(a1===a2){
    return true;
  }else{
    var count=0;
    for(i=0;i<a2.length;i++){
      for(j=0;j<a1.length;j++){
        if(a2[i]==a1[j]){
          count+=1;
        }
      }
    }
    if(count>=a2.length){
      return true;
    }else{
      return false;
    }
  }
}
2017.1更新:
现在看来真心不叫直接
function mutation(arr) {
arr[0]=arr[0].toLowerCase();
arr[1]=arr[1].toLowerCase(); for(var i=0;i<arr[1].length;i++){
if(arr[0].indexOf(arr[1][i])==-1){
return false;
}
}
return true;
}
13.删除数组中的所有假值。
在JavaScript中,假值有false、null、0、""、undefined 和 NaN。
function bouncer(arr) {
  // Don't show a false ID to this bouncer.
  arr=arr.filter(function(a){
    return a
  });
  return arr;
}
bouncer([7, "ate", "", false, 9])
14.实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值。
思路:要逐步判断arr内的每个参数值,满足一样的删除掉即可,但是在循环内删除会破坏结构,所以可以先替换为一个false,然后再来用filter判断返回出真值。
function destroyer(arr) {
  // Remove all the values
  for(i=1;i<arguments.length;i++){
    for(j=0;j<arr.length;j++){
      if(arr[j]==arguments[i]){
        arr.splice(j,1,"false");//起始项数,要删除的值数,添加项内容
        // 原来的代码是 arr.splice(j,1,false);经过网友提示应该改为别的flag量
      }
    }
  }
  arr=arr.filter(function(a){
    return a!=="false";
  });
  return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
2017.1更新
这貌似是聊天室里要源码最多的问题之一。于是我看到了这种解法
Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组.
function destroyer(arr) {
// Remove all the values
var mainArr = arguments[0],
filtArr = Array.prototype.slice.call(arguments, 1); return mainArr.filter(function(value,index){
return filtArr.indexOf(value) === -1;
}); } destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3);
15.先给数组排序,然后找到指定的值在数组的位置,最后返回位置对应的索引。
举例:where([1,2,3,4], 1.5) 应该返回 1。因为1.5插入到数组[1,2,3,4]后变成[1,1.5,2,3,4],而1.5对应的索引值就是1。
同理,where([20,3,5], 19) 应该返回 2。因为数组会先排序为 [3,5,20],19插入到数组[3,5,20]后变成[3,5,19,20],而19对应的索引值就是2。
思路:用一个索引值index来标记num本应在数组的位置。在遍历比较之后插入数组。
function where(arr, num) {
  // Find my place in this sorted array.
  arr.sort(function(a,b){
    return a-b;
  });
  var index=0;
  for(i=0;i<arr.length;i++){
    if(arr[i]<num){
      index+=1;
    }
  }
  arr.splice(index,0,num);
   console.log(arr);
  return index;
}
where([40, 60], 50);
2017.1更新
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;
}
}
}
16.下面我们来介绍风靡全球的凯撒密码Caesar cipher,又叫移位密码。
移位密码也就是密码中的字母会按照指定的数量来做移位。
一个常见的案例就是ROT13密码,字母会移位13个位置。由'A' ↔ 'N', 'B' ↔ 'O',以此类推。
写一个ROT13函数,实现输入加密字符串,输出解密字符串。
所有的字母都是大写,不要转化任何非字母形式的字符(例如:空格,标点符号),遇到这些特殊字符,跳过它们。
思路:
(1)每个字符都有自己的键码,相关的编码可以在键码表查到。根据需求:大写字母A-Z的键码为60-90。只要获取每个字符串的键码(String.charCodeAt()方法),回退13位,就可以获得解密后的键码。最后把它输出为相应的字母(String.fromCharCode()方法)。
(2)首先要判断的是:键码60-90闭区间外的字符不予编译。
(3)其次,明文的键码解密之后可能退到不属于大写字母的编码区,比如加密明文为A的时,直接回退再编译就变成了数字3,因此需要给它在此基础上加上大写字母表的个数26。再进行判断。这实现了整个编译区相对于明文区的偏移。
function rot13(str){ // LBH QVQ VG!
  var newStr='';
  for(i=0;i<str.length;i++){
    if(str[i].charCodeAt(0)>90||str[i].charCodeAt(0)<65){
      newStr+=str[i];
    }else{
      var newStrCode=str[i].charCodeAt(0)-13;
      if(newStrCode<65){
        newStrCode+=26;
      }
      newStr+=String.fromCharCode(newStrCode);
    }
  }
  return (newStr);
}
// Change the inputs below to test
rot13("LBH QVQ VG");
题目来源:
FCC中文网:https://www.freecodecamp.cn/
参考资料:
[1]《javascript高级程设计》第4,5,6章。
[2] MOZILLA开发者社区:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
[3]W3school: http://www.w3school.com.cn/
[4]感谢gitter中文聊天室热心的网友
FCC上的初级算法题的更多相关文章
- FCC上的javascript算法题之中级篇
		
FCC中的javascript中级算法题解答 中级算法的题目中用到了很多js的知识点,比如迭代,闭包,以及对json数据的使用等等,现在将自己中级算法的解答思路整理出来供大家参考讨论.欢迎大家提出新的 ...
 - FCC的javascript初级算法题解答
		
FCC上的javascript基础算法题 前一阵子做的基础算法题,感觉做完后收获还蛮大的,现在将自己的做法总结出来,供大家参考讨论.基本上做到尽量简短有效,但有些算法还可以继续简化,比如第七题若采用正 ...
 - 简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现。
		
简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现. 题目: Suppose a sorted array is rotated at som ...
 - [java大数据面试] 2018年4月百度面试经过+三面算法题:给定一个数组,求和为定值的所有组合.
		
给定一个数组,求和为定值的所有组合, 这道算法题在leetcode应该算是中等偏下难度, 对三到五年工作经验主要做业务开发的同学来说, 一般较难的也就是这种程度了. 简述经过: 不算hr面,总计四面, ...
 - 前端如何应对笔试算法题?(用node编程)
		
用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...
 - fcc的中级算法题
		
核心提示:这是网上开源编程学习项目FCC的javascript中级编程题(Intermediate Algorithm Scripting(50 hours)),一共20题.建议时间是50个小时,对于 ...
 - Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全  C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数  C# 算法题系列(一) 两数之和、无重复字符的最长子串  DateTime Tips  c#发送邮件,可发送多个附件  MVC图片上传详解
		
Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全 Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...
 - 面试经典算法题集锦——《剑指 offer》小结
		
从今年 3 月份开始准备找实习,到现在校招结束,申请的工作均为机器学习/数据挖掘算法相关职位,也拿到了几个 sp offer.经历这半年的洗礼,自己的综合能力和素质都得到了一个质的提升. 实话说对于未 ...
 - LeetCode初级算法的Python实现--链表
		
LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...
 
随机推荐
- java-URLConnection网络数据收取
			
通过url创建connection方式收取 import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import ja ...
 - python Chrome 开发者模式消失的方法
			
最近使用 Chrome浏览器跑Selenium Python 自动化脚本运行过程中,总是出现这样的对话框 出现这样的对话框,如果不能自动关闭,这个对话框会影响web端页面的其他链接的定位识别,这样就 ...
 - 【POJ 1789】Truck History(最小生成树)
			
题意:距离定义为两个字符串的不同字符的位置个数.然后求出最小生成树. #include <algorithm> #include <cstdio> #include <c ...
 - 【LintCode】计算两个数的交集(二)
			
问题分析: 用两个指针分别遍历即可. 问题求解: public class Solution { /** * @param nums1 an integer array * @param nums2 ...
 - 【转】Handler学习笔记(一)
			
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
 - Firefox上运行自动化测试脚本提示元素无法点击“WebDriverException: Message: Element is not clickable at point“解决方法
			
1. Firefox上运行脚本时提示“WebDriverException: Message: Element is not clickable at point (934.316650390625, ...
 - python模块介绍二。
			
全局变量 全局变量 python在一个.py文件内部自动添加了一些全局变量 print(vars()) #查看当前的全局变量 执行结果: {'__package__': None, '__loader ...
 - BIEE定制化
			
(1)自定义图片的引用 (2)修改产品本身的一些图片内容 (3)修改产品本身的一些文字 如何引用自己的自定义图片: 直接找路径或者图片就可以修改 推荐不要直接替换,直接替换导致有的内容没办法直接显示出 ...
 - springMVC-mvc:annotation-driven
			
<mvc:annotation-driven/>会自动注册 RequestMappingHandlerMapping RequestMappingHandlerAdapter Except ...
 - Python基础4:数据类型:数字 字符串 日期
			
[ Python 数据类型 ] 我们知道,几乎任何编程语言都具有数据类型:常见的数据类型有:字符串.整型.浮点型以及布尔类型等. Python也不例外,也有自己的数据类型,主要有以下几种: 1.数字: ...