首页 > 代码库 > 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
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