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}).

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。

我们可以通过表格来更直观地查看数组中索引和值的关系:

 

Index01234
Value79111315

 

 思路:以为是个压轴题,结果不是、、、就是判断是否配对,把索引值相加。但要记住,每个索引值只能用一次,所以用掉的索引,要赋值为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个小时,就个人做下来花的时间还是挺长的,很多题都是花了一天做出来,然后想办法优化,提升运行速度,减少代码量。虽然很多题目在实现运用中可能体现不了,也不会那么复杂。但是程序思维还是应该培养的。

 

转载于:https://www.cnblogs.com/skylin0909/p/6096210.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值