1.Validate US Telephone Numbers
如果传入字符串是一个有效的美国电话号码,则返回 true
.
用户可以在表单中填入一个任意有效美国电话号码. 下面是一些有效号码的例子(还有下面测试时用到的一些变体写法):
555-555-5555 (555)555-5555 (555) 555-5555 555 555 5555 5555555555 1 555 555 5555 1 555-555-5555 1 (555) 555-5555 |
在本节中你会看见如 800-692-7753
or 8oo-six427676;laskdjf
这样的字符串. 你的任务就是验证前面给出的字符串是否是有效的美国电话号码. 区号是必须有的. 如果字符串中给出了国家代码, 你必须验证其是 1
. 如果号码有效就返回 true
; 否则返回 false;
思路:先判定国家代码,在来判断后面10位数的格式是否满足需要。后面10位数字里又要注意前3位区号是否带括号的情况。所以 应该是两正则用|分组一个正则搞定
1 function telephoneCheck(str) { 2 //定义一个正则匹配不含区号的情况 3 var re = /^\(\d{3}\)[- ]?\d{3}[- ]\d{4}$|^\d{3}[ -]?\d{3}[ -]?\d{4}$/; 4 //判断第一个数字是否为1 5 if(str[0] == 1){ 6 //如果是1,且紧挨着1后面的是括号,可去掉第一个字符调用正则 7 if(str[1] === "\("){ 8 return re.test(str.slice(1)); 9 } 10 //如果是1,且紧挨着1后面的不是是括号那么要想符合要求第二个字符必定为空格 11 //可去掉前两个字符调用正则 12 else{ 13 return re.test(str.slice(2)); 14 } 15 } 16 return re.test(str); 17 }
2.Symmetric Difference
创建一个函数,接受两个或多个数组,返回所给数组的 对等差分(symmetric difference)(△
or ⊕
)数组.
给出两个集合 (如集合 A = {1, 2, 3}
和集合 B = {2, 3, 4}
), 而数学术语 "对等差分" 的集合就是指由所有只在两个集合其中之一的元素组成的集合(A △ B = C = {1, 4}
). 对于传入的额外集合 (如 D = {2, 3}
), 你应该安装前面原则求前两个集合的结果与新集合的对等差分集合 (C △ D = {1, 4} △ {2, 3} = {1, 2, 3, 4}
).
function sym(args) { return args; } sym([1, 2, 3], [5, 2, 1, 4]); sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]) 应该返回 [1, 4, 5]; sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]) 应该返回 [2, 3, 4, 6, 7]; sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1]) 应该返回 [1, 2, 4, 5, 6, 7, 8, 9];
思路:args为一个伪数组,所以先转换成二维数组,在逐一比较相邻两数组的差异,返回一个新数组,如果二维数组不止2项,再用这个新数组再做判断。所以用到reduce(),和filter()。注意!因为相互比较之后,会有重复的数字,所以需去重。
1 function sym(args) { 2 //将参数转换为数组 3 var arr = Array.from(arguments); 4 //求出将要测试的数组 5 var tempArr = arr.reduce(function(prev,cur,index,arr){ 6 var a = prev.filter(function(item){ 7 return cur.indexOf(item) < 0; 8 }); 9 var b = cur.filter(function(item){ 10 return prev.indexOf(item) < 0; 11 }); 12 return a.concat(b); 13 }); 14 //去重 15 return tempArr.filter(function(item,index,array){ 16 return array.indexOf(item) == index; 17 }); 18 }
3.Exact Change
设计一个收银程序 checkCashRegister()
,其把购买价格(price
)作为第一个参数 , 付款金额 (cash
)作为第二个参数, 和收银机中零钱 (cid
) 作为第三个参数.
cid
是一个二维数组,存着当前可用的找零.
当收银机中的钱不够找零时返回字符串"Insufficient Funds"
. 如果正好则返回字符串"Closed"
.
否则, 返回应找回的零钱列表,且由大到小存在二维数组中.(漏掉了原题目,之后我会加上)
1 function checkCashRegister(price, cash, cid) { 2 var change; 3 // Here is your change, ma'am. 4 return change; 5 } 6 7 // Example cash-in-drawer array: 8 // [["PENNY", 1.01], 9 // ["NICKEL", 2.05], 10 // ["DIME", 3.10], 11 // ["QUARTER", 4.25], 12 // ["ONE", 90.00], 13 // ["FIVE", 55.00], 14 // ["TEN", 20.00], 15 // ["TWENTY", 60.00], 16 // ["ONE HUNDRED", 100.00]] 17 18 checkCashRegister(19.50, 20.00, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]);
思路:这道题其实不难,就是异常的麻烦。感觉题目有给一定的提示,就是它注释起来那个array.因为涉及都美分,所以要乘以一个基数100来简化运算。再一个,常规思维,如果找零的时候,有1张20,肯定不会去用2张10元的。
1 //创建一个面额的对象数组 2 var denom = [ 3 { name: 'ONE HUNDRED', val: 100.00}, 4 { name: 'TWENTY', val: 20.00}, 5 { name: 'TEN', val: 10.00}, 6 { name: 'FIVE', val: 5.00}, 7 { name: 'ONE', val: 1.00}, 8 { name: 'QUARTER', val: 0.25}, 9 { name: 'DIME', val: 0.10}, 10 { name: 'NICKEL', val: 0.05}, 11 { name: 'PENNY', val: 0.01} 12 ]; 13 function checkCashRegister(price, cash, cid) { 14 //需要找零的钱 15 var change = cash - price; 16 //把收银台的钱求和,同时转变成一个对象 17 var register = cid.reduce(function(prev, curr) { 18 prev.total += curr[1]; 19 prev[curr[0]] = curr[1]; 20 return prev; 21 }, {total: 0}); 22 //简单的判断 23 if (register.total === change) { 24 return 'Closed'; 25 } 26 if (register.total < change) { 27 return 'Insufficient Funds'; 28 } 29 30 // 循环我们之前定义的二维数组,并求出我们想要返回的面值数组 31 var change_arr = denom.reduce(function(prev, curr) { 32 var value = 0; 33 //把收银台里的面值从大到小的去筛选,并判断这张面值能否找零 34 while (register[curr.name] > 0 && change >= curr.val) { 35 change -= curr.val;//满足条件就扣除这么大的一张面值,好比总共找零60,先给一张50 36 register[curr.name] -= curr.val;//同时收银台 37 value += curr.val; 38 //熟悉的朋友知道JavaScript精度的问题,很多时候2其实是1.999999999999,所以这里处理下。 39 change = Math.round(change * 100) / 100; 40 } 41 // 如果value有值,就可以加入要返回的数组了,否则比较下一阶的面值 42 if (value > 0) { 43 prev.push([ curr.name, value ]); 44 } 45 return prev; 46 }, []); 47 //数组里没有值 ,或者需要找零的钱不够 48 if (change_arr.length < 1 || change > 0) { 49 return "Insufficient Funds"; 50 } 51 return change_arr; 52 }
4.Inventory Update
依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1
中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. 返回当前的库存数组,且按货物名称的字母顺序排列.
1 function updateInventory(arr1, arr2) { 2 // All inventory must be accounted for or you're fired! 3 return arr1; 4 } 5 6 // Example inventory lists 7 var curInv = [ 8 [21, "Bowling Ball"], 9 [2, "Dirty Sock"], 10 [1, "Hair Pin"], 11 [5, "Microphone"] 12 ]; 13 14 var newInv = [ 15 [2, "Hair Pin"], 16 [3, "Half-Eaten Apple"], 17 [67, "Bowling Ball"], 18 [7, "Toothpaste"] 19 ]; 20 21 updateInventory(curInv, newInv);
思路:就是大学里小卖部进货,巧克力面包有的,就把数量累计。新来的苹果面包没有,就直接入库。同时苹果面包是A开头,巧克力面包是C开头,所以苹果面包在返回的数组中应该排在前面。纯粹就是考察数组的知识点。代码注释会具体讲
1 function updateInventory(arr1, arr2) { 2 //定义空数组,然后在把arr1整个数组copy给它,很多人会问为什么不能arr = arr1; 3 //因为数组是引用类型,如果用=赋值,他们其实指向的是一个地址,会面的代码有可能会报错 4 var arr = []; 5 arr = arr1.map(function(item){ 6 return item; 7 }) 8 //思路很简单,将第二个数组的每个元素与库存作比较,有,就把数值累加,没有就直接插入 9 for(var i = 0;i < arr2.length;i++){ 10 var flag = true; 11 for(var j = 0; j < arr1.length; j++){ 12 if (arr2[i][1] == arr1[j][1]){ 13 arr1[j][0] += arr2[i][0]; 14 arr.push(arr1[j]); 15 flag = false; 16 } 17 } 18 if(flag){ 19 arr.push(arr2[i]); 20 } 21 } 22 //去重 23 var tempArr = arr.filter(function(item,index,array){ 24 return array.indexOf(item) == index; 25 }); 26 //排序 27 return tempArr.sort(function(a,b){ 28 return (a[1][0]>b[1][0])? 1 : 0; 29 }); 30 }
5.No repeats please
把一个字符串中的字符重新排列生成新的字符串,返回新生成的字符串里没有连续重复字符的字符串个数.连续重复只以单个字符为准
例如, aab
应该返回 2 因为它总共有6中排列 (aab
, aab
, aba
, aba
, baa
, baa
), 但是只有两个 (aba
and aba
)没有连续重复的字符 (在本例中是 a
).
function permAlone(str) { return str; } permAlone('aab'); permAlone("aabb") //应该返回 8. permAlone("abcdefa")// 应该返回 3600. permAlone("abfdefa")// 应该返回 2640.
思路:这是一道送命题啊,讲真是真的难,用数学思维我都解不出来,程序思维倒是好想,实现起来难度真的大,这应该是9道题中最难的!
1 function permAlone(str) { 2 var re = /(.)\1+/g, 3 arr = str.split(''), 4 newArr = []; 5 //全部相等时返回0 6 if (str.match(re) !== null && str.match(re)[0] === str) return 0; 7 // 创建一个交换函数来交换变量的内容 8 var temp; 9 function change(index1, index2) { 10 temp = arr[index1]; 11 arr[index1]=arr[index2]; 12 arr[index2]=temp; 13 } 14 //创建递归函数,生成所情况的组合 15 16 function generate(n) { 17 //递归至只身下一个的时候,可以返回这个数组了。 18 if(n === 1){ 19 newArr.push(arr.join('')); 20 } 21 else{ 22 //重点就是这里,整个题目所有所有的关键就这两步! 23 for(var i=0; i<n;i++){ 24 //自身调用,挨个排好 25 generate(n-1); 26 //奇数取0,偶数取i 27 change(n % 2? 0 : i, n - 1); 28 } 29 } 30 } 31 //调用函数,然后去掉不符合要求的元素,再返回长度 32 generate(arr.length); 33 var result = newArr.filter(function(string) { 34 return !string.match(re); 35 }); 36 return result.length; 37 }
6.Friendly Date Ranges
把常见的日期格式如:YYYY-MM-DD
转换成一种更易读的格式。
易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st
代替 1
).
记住不要显示那些可以被推测出来的信息: 如果一个日期区间里结束日期与开始日期相差小于一年,则结束日期就不用写年份了。月份开始和结束日期如果在同一个月,则结束日期月份就不用写了。
另外, 如果开始日期年份是当前年份,且结束日期与开始日期小于一年,则开始日期的年份也不用写。
例如:
makeFriendlyDates(["2016-07-01", "2016-07-04"]) 应该返回 ["July 1st","4th"]
makeFriendlyDates(["2016-07-01", "2018-07-04"]) 应该返回 ["July 1st, 2016", "July 4th, 2018"].
function makeFriendlyDates(arr) { return arr; } makeFriendlyDates(["2016-07-01", "2016-07-04"]) should return ["July 1st","4th"]. makeFriendlyDates(["2016-12-01", "2017-02-03"]) should return ["December 1st","February 3rd"]. makeFriendlyDates(["2016-12-01", "2018-02-03"]) should return ["December 1st, 2016","February 3rd, 2018"]. makeFriendlyDates(["2017-03-01", "2017-05-05"]) should return ["March 1st, 2017","May 5th"] makeFriendlyDates(["2018-01-13", "2018-01-13"]) should return ["January 13th, 2018"]. makeFriendlyDates(["2022-09-05", "2023-09-04"]) should return ["September 5th, 2022","September 4th"]. makeFriendlyDates(["2022-09-05", "2023-09-05"]) should return ["September 5th, 2022","September 5th, 2023"].
思路:其实题目本身不难,主要是其中的逻辑太多,无法简单的判断就返回值,而且为了兼容发生在今年之前,或者闰年,闰月的情况,情况很是复杂,注释我已经写的非常清楚了,应该能理解。
1 function makeFriendlyDates(arr) { 2 //创建基本数组,注意索引从0开始,所以日期和月份数组的第一个字符为空。 3 var dateArr = ["","1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th", 4 "11th","12th","13th","14th","15th","16th","17th","18th","19th","20th", 5 "21st","22nd","23rd","24th","25th","26th","27th","28th","29th","30th", 6 "31st"], 7 monthArr = ["","January","February","March","April","May","June", 8 "July","August","September","October","November","December"], 9 result = [], 10 temparr1 = arr[0].split("-"), 11 temparr2 = arr[1].split("-"); 12 //当前的四位数年份 13 var nowYear = new Date().getFullYear(); 14 //创建用于判断的年丶月丶日 15 var year1 = temparr1[0], 16 month1 = temparr1[1], 17 date1 = temparr1[2], 18 year2 = temparr2[0], 19 month2 = temparr2[1], 20 date2 = temparr2[2]; 21 //年丶月丶日的差值 22 var Y = year2 - year1, 23 M = month2 - month1, 24 D = date2 - date1; 25 //转换最后需要输出的月丶日 26 var remonth1 = monthArr[parseInt(month1)], 27 redate1 = dateArr[parseInt(date1)], 28 remonth2 = monthArr[parseInt(month2)], 29 redate2 = dateArr[parseInt(date2)]; 30 //开始判断区间大于1年的情况 31 if(Y > 1 || (Y == 1 && M >= 1) || (Y == 1 && M == 0 && D >= 0)){ 32 var result1 = remonth1+" "+redate1+", "+year1; 33 var result2 = remonth2+" "+redate2+", "+year2; 34 result.push(result1); 35 result.push(result2); 36 } 37 //判断小于1年的第一种情况--年份不同 38 else if(Y == 1 && M < 1){ 39 if(year1 == nowYear){ 40 var result1 = remonth1+" "+redate1; 41 var result2 = remonth2+" "+redate2; 42 result.push(result1); 43 result.push(result2); 44 } 45 else{ 46 var result1 = remonth1+" "+redate1+", "+year1; 47 var result2 = remonth2+" "+redate2; 48 result.push(result1); 49 result.push(result2); 50 } 51 } 52 //判断小于1年的第二种情况--年份相同 53 else{ 54 if(M == 0){ 55 //同月同日 56 if(D == 0){ 57 if (year1 == nowYear) { 58 var result1 = remonth1+" "+redate1; 59 result.push(result1); 60 } 61 else{ 62 var result1 = remonth1+" "+redate1+", "+year1; 63 result.push(result1); 64 } 65 } 66 //同月不同日 67 else{ 68 var result1 = remonth1+" "+redate1; 69 var result2 = redate2; 70 result.push(result1); 71 result.push(result2); 72 } 73 } 74 //不同月 75 else{ 76 var result1 = remonth1+" "+redate1+", "+year1; 77 var result2 = remonth2+" "+redate2; 78 result.push(result1); 79 result.push(result2); 80 } 81 } 82 return result; 83 }
7.Make a Person
用下面给定的方法构造一个对象.
方法有 getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).
所有有参数的方法只接受一个字符串参数.
所有的方法只与实体对象交互.
var Person = function(firstAndLast) { return firstAndLast; }; var bob = new Person('Bob Ross'); bob.getFullName(); bob.getFirstName() 应该返回 "Bob". bob.getLastName() 应该返回 "Ross". bob.getFullName() 应该返回 "Bob Ross". bob.getFullName() 应该返回 "Haskell Ross" after bob.setFirstName("Haskell"). bob.getFullName() 应该返回 "Haskell Curry" after bob.setLastName("Curry"). bob.getFullName() 应该返回 "Haskell Curry" 在 bob.setFullName("Haskell Curry") 之后. bob.getFirstName() 应该返回 "Haskell" 在 bob.setFullName("Haskell Curry") 之后. bob.getLastName() 应该返回 "Curry" 在 bob.setFullName("Haskell Curry") 之后.
思路:我觉得这题出的没意义啊,看似考察对象和闭包,然后其实还是数组的知识多一点。希望FCC上有构造原型函数和面向对象之类的训练。就注意一个splice().
1 function Person(fullName){ 2 3 this.getFirstName=function(){ 4 return fullName.split(' ')[0]; 5 }; 6 this.getLastName=function(){ 7 return fullName.split(' ')[1]; 8 }; 9 this.getFullName=function(){ 10 return fullName; 11 }; 12 13 this.setFirstName=function(first){ 14 var arr=fullName.split(' '); 15 arr.splice(0,1,first); 16 fullName=arr.join(' '); 17 }; 18 this.setLastName=function(last){ 19 var arr=fullName.split(' '); 20 arr.splice(1,1,last); 21 fullName=arr.join(' '); 22 }; 23 this.setFullName=function(firstAndLast){ 24 fullName=firstAndLast; 25 }; 26 27 }
8.Map the Debris
返回一个数组,其内容是把原数组中对应元素的平均海拔转换成其对应的轨道周期.
原数组中会包含格式化的对象内容,像这样{name: 'name', avgAlt: avgAlt}
.
至于轨道周期怎么求,戳这里 on wikipedia (不想看英文的话可以自行搜索以轨道高度计算轨道周期的公式).
求得的值应该是一个与其最接近的整数,轨道是以地球为基准的.
地球半径是 6367.4447 kilometers, 地球的GM值是 398600.4418, 圆周率为Math.PI
function orbitalPeriod(arr) { var GM = 398600.4418; var earthRadius = 6367.4447; return arr; } orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]) 应该返回 [{name: "sputnik", orbitalPeriod: 86400}]; orbitalPeriod([{name: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]) 应该返回 [{name : "iss", orbitalPeriod: 5557}, {name: "hubble", orbitalPeriod: 5734}, {name: "moon", orbitalPeriod: 2377399}];
思路:这道题考的高中物理知识,友情链接里有。这题我是抄的,因为公式我也忘了。把答案给出来吧,没什么好讲的
1 function orbitalPeriod(arr) { 2 var GM = 398600.4418; 3 var earthRadius = 6367.4447; 4 for(var i=0;i<arr.length;i++){ 5 var R=(arr[i].avgAlt+6367.4447); 6 var T=R*2*Math.PI*Math.sqrt((R/GM)); 7 delete arr[i].avgAlt; 8 arr[i].orbitalPeriod=Math.round(T); 9 } 10 11 console.log(arr); 12 return arr; 13 }
9.Pairwise
找到你的另一半
都说优秀的程序员擅长面向对象编程,但却经常找不到另一半,这是为什么呢?因为你总是把自己局限成为一个程序员,没有打开自己的思维。
这是一个社群的时代啊,在这里你应该找到与你有相同价值观但又互补的另一半。
譬如:你编程能力强,估值11分,如果以20分为最佳情侣来计算,你应该找一个设计能力强,估值为9分的女生。
那么当你遇到一个设计能力为9分的女生,千万别犹豫,大胆去表白。千万别以为后面的瓜比前面的甜哦。
举个例子:有一个能力数组[7,9,11,13,15]
,按照最佳组合值为20来计算,只有7+13和9+11两种组合。而7在数组的索引为0,13在数组的索引为3,9在数组的索引为1,11在数组的索引为2。
所以我们说函数:pairwise([7,9,11,13,15],20)
的返回值应该是0+3+1+2的和,即6。
我们可以通过表格来更直观地查看数组中索引和值的关系:
Index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Value | 7 | 9 | 11 | 13 | 15 |
思路:以为是个压轴题,结果不是、、、就是判断是否配对,把索引值相加。但要记住,每个索引值只能用一次,所以用掉的索引,要赋值为null,undefined都可以
1 function pairwise(arr, arg) { 2 var sum = 0, 3 len = arr.length; 4 for(var i = 0; i < len; i++){ 5 for(var j = i+1;j < len; j++){ 6 if(arr[i]+arr[j] == arg){ 7 sum =sum + i +j; 8 arr[i] = "null"; 9 arr[j] = "null"; 10 } 11 } 12 } 13 return sum; 14 }
总结:
好了!总算写完了这9道题。题目给的是50个小时,就个人做下来花的时间还是挺长的,很多题都是花了一天做出来,然后想办法优化,提升运行速度,减少代码量。虽然很多题目在实现运用中可能体现不了,也不会那么复杂。但是程序思维还是应该培养的。