首页 > 代码库 > FCC Advanced Algorithm Scripting
FCC Advanced Algorithm Scripting
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}
).
思路: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 = http://www.mamicode.com/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 }
好了,后面的3道题,其实就不怎么难了,由于时间关系。今天先写到这里。明儿有空再补上
FCC Advanced Algorithm Scripting