高级脚本算法挑战
地址:https://www.w3cschool.cn/codecamp/list?pename=advanced_algorithm_scripting_camp
判断电话号码算法挑战:
如果传入字符串是一个有效的美国电话号码,则返回 true.
用户可以在表单中填入一个任意有效美国电话号码. 下面是一些有效号码的例子(还有下面测试时用到的一些变体写法):
555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555
在本节中你会看见如 800-692-7753 or 8oo-six427676;laskdjf这样的字符串. 你的任务就是验证前面给出的字符串是否是有效的美国电话号码. 区号是必须有的. 如果字符串中给出了国家代码, 你必须验证其是 1.如果号码有效就返回 true ; 否则返回 false.
function telephoneCheck(str) { return /^1?\s?(\(\d{3}\)|\d{3})[-|\s]*\d{3}[-|\s]*\d{4}$/.test(str); //return /^1? ?(\d{3}|\(\d{3}\))[ -]?\d{3}[ -]?\d{4}$/.test(str); } telephoneCheck("555-555-5555");
集合交集算法挑战:
创建一个函数,接受两个或多个数组,返回所给数组的 对等差分(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(result,...args) { for(let i=0,j=args.length;i<j;i++) { result = result.filter(a=>args[i].indexOf(a)<0).concat(args[i].filter(a=>result.indexOf(a)<0)); result = [...new Set(result)]; } return result; } sym([1, 2, 3], [5, 2, 1, 4]);
收银系统算法挑战:
设计一个收银程序 checkCashRegister() ,其把购买价格(price)作为第一个参数 , 付款金额 (cash)作为第二个参数, 和收银机中零钱 (cid) 作为第三个参数.
cid 是一个二维数组,存着当前可用的找零.
当收银机中的钱不够找零时返回字符串 "Insufficient Funds". 如果正好则返回字符串 "Closed".
否者, 返回应找回的零钱列表,且由大到小存在二维数组中.
function checkCashRegister(price, cash, cid) { //排序 //cid.sort(function(a,b){ return b[1]-a[1]}); //求和 let sum = 100 * cid.reduce(function(a,b){ return Array.isArray(a)?a[1]+b[1]:a+b[1];}) let diff =100 * (cash - price); if(sum > diff) { let result = []; let num = 0; let initMoney = 100 * cid[8][1]; let outMoney = 0; while(diff>=10000) { if(initMoney<=0) { break; } num++; outMoney += 10000; diff -= 10000; initMoney -=10000; } if(num>0) { result.push(["ONE HUNDRED",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[7][1]; outMoney = 0; while(diff>=2000) { if(initMoney<=0) { break; } num++; outMoney += 2000; diff -= 2000; initMoney -=2000; } if(num>0) { result.push(["TWENTY",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[6][1]; outMoney = 0; while(diff>=1000) { if(initMoney<=0) { break; } num++; outMoney += 1000; diff -= 1000; initMoney -=1000; } if(num>0) { result.push(["TEN",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[5][1]; outMoney = 0; while(diff>=500) { if(initMoney<=0) { break; } num++; outMoney += 500; diff -= 500; initMoney -=500; } if(num>0) { result.push(["FIVE",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[4][1]; outMoney = 0; while(diff>=100) { if(initMoney<=0) { break; } num++; outMoney += 100; diff -= 100; initMoney -=100; } if(num>0) { result.push(["ONE",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[3][1]; outMoney = 0; while(diff>= 25) { if(initMoney<=0) { break; } num++; outMoney += 25; diff -= 25; initMoney -= 25; } if(num>0) { result.push(["QUARTER",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[2][1]; outMoney = 0; while(diff>=10) { if(initMoney<=0) { break; } num++; outMoney += 10; diff -= 10; initMoney -= 10; } if(num>0) { result.push(["DIME",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[1][1]; outMoney = 0; while(diff>=5) { if(initMoney<=0) { break; } num++; outMoney += 5; diff -= 5; initMoney -= 5; } if(num>0) { result.push(["NICKEL",Number(outMoney/100)]); } num = 0; initMoney = 100 * cid[0][1]; outMoney = 0; while(diff>=1) { if(initMoney<=0) { break; } num++; outMoney += 1; diff -= 1; initMoney -=1; } console.log(diff); if(num>0) { result.push(["PENNY",Number(outMoney/100)]); } if(diff>0) { return "Insufficient Funds"; } return result; } else if(sum == diff){ return "Closed"; } else { return "Insufficient Funds"; } } 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]]);
库存更新算法挑战:
依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1 中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. 返回当前的库存数组,且按货物名称的字母顺序排列.
function updateInventory(arr1, arr2) { let result = arr2; if(arr2.length == 0) { return arr1; } let arr = []; arr2.reduce(function(a,b){if(a!=undefined){arr.push(a[1]);}arr.push(b[1]);}); for(let i = 0 ,j=arr1.length;i<j;i++) { var index = arr.indexOf(arr1[i][1]); if ( index < 0 ) { result.push(arr1[i]); } else { result = result.slice(0,index).concat([[result.slice(index,index+1)[0][0]+arr1[i][0],result.slice(index,index+1)[0][1]]]).concat(result.slice(index+1,result.length)); } } result.sort(function(a,b){return b[1]<a[1]}); console.log(result); return result; } // Example inventory lists var curInv = [ [21, "Bowling Ball"], [2, "Dirty Sock"], [1, "Hair Pin"], [5, "Microphone"] ]; var newInv = [ [2, "Hair Pin"], [3, "Half-Eaten Apple"], [67, "Bowling Ball"], [7, "Toothpaste"] ]; updateInventory(curInv, newInv);
排列组合去重算法挑战:
把一个字符串中的字符重新排列生成新的字符串,返回新生成的字符串里没有连续重复字符的字符串个数.连续重复只以单个字符为准
例如, aab 应该返回 2 因为它总共有6中排列 (aab, aab, aba, aba, baa, baa), 但是只有两个 (aba and aba)没有连续重复的字符 (在本例中是 a).
function permAlone(str) { let result = []; for(let i=0,j=str.length;i<j;i++) { if(i==0){ result.push([str[i]]); continue; } let temp = result.concat(); result = []; for(let i1 = 0,j1 = temp.length; i1 < j1; i1++) { for(let i2 = 0,j2 = temp[i1].length ; i2<=j2 ;i2++) { result.push(temp[i1].slice(0,i2).concat([str[i]]).concat(temp[i1].slice(i2,j2))); } } } let count = 0; for(let i = 0,j=result.length;i<j;i++) { for(let i1=0,j1=result[i].length;i1<j1-1;i1++) { if(result[i][i1]==result[i][i1+1]) { break; } else if(i1==j1-2) { count++; } } } return count; } permAlone('aab');
日期改写算法挑战:
让日期区间更友好!
把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式。
易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1).
记住不要显示那些可以被推测出来的信息: 如果一个日期区间里结束日期与开始日期相差小于一年,则结束日期就不用写年份了。月份开始和结束日期如果在同一个月,则结束日期月份就不用写了。
另外, 如果开始日期年份是当前年份,且结束日期与开始日期小于一年,则开始日期的年份也不用写。
例如:
makeFriendlyDates(["2016-07-01", "2016-07-04"]) 应该返回 ["July 1st, 2016","4th"]
makeFriendlyDates(["2016-07-01", "2018-07-04"]) 应该返回 ["July 1st, 2016", "July 4th, 2018"].
function makeFriendlyDates(arr) { let result = []; let year; let month; let day; for(let i =0,j=arr.length;i<j;i++) { if(i==0) { arr[i].split("-").reduce(function(a,c,i){if(a!=undefined){year=a;} if(i==1){month=c;}else{day=c;}}); result.push(getMonth(month)+" "+Number(day)+getDay(day)+", "+year); } else if(i==1) { let tempYear,tempMonth,tempDay; arr[i].split("-").reduce(function(a,c,i){if(a!=undefined){tempYear=a;} if(i==1){tempMonth=c;}else{tempDay=c;}}); let oneYear = new Date(year-1,month,day).getTime() < new Date(tempYear,tempMonth,tempDay).getTime() && new Date(Number(year)+1,month,day).getTime()> new Date(tempYear,tempMonth,tempDay).getTime() ; if(tempYear != year && !oneYear ) { result.push(getMonth(tempMonth)+" "+Number(tempDay)+getDay(tempDay)+", "+tempYear); } else if(tempMonth != month || (tempYear != year && oneYear && tempMonth == month) ) { result.push(getMonth(tempMonth)+" "+Number(tempDay)+getDay(tempDay)); } else if(tempDay != day) { result.push(Number(tempDay)+getDay(tempDay)); } } } return result; } function getMonth(month) { switch (month) { case '01': return "January" break; case '02': return "February" break; case '03': return "March" break; case '04': return "April" break; case '05': return "May" break; case '06': return "June" break; case '07': return "July" break; case '08': return "August" break; case '09': return "September" break; case '10': return "October" break; case '11': return "November" break; case '12': return "December" break; default: return ""; } } function getDay(day) { switch (day) { case '01': case '21': case '31': return "st" break; case '02': case '22': return "nd" break; case '03': case '23': return "rd" break; default: return "th"; } } makeFriendlyDates(['2016-07-01', '2016-07-04']);
类及对象构建算法挑战:
用下面给定的方法构造一个对象.
方法有 getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).
所有有参数的方法只接受一个字符串参数.
所有的方法只与实体对象交互.
var Person = function(firstAndLast) { this.getFirstName= function(){ return firstAndLast.split(" ")[0]} , this.getLastName=function(){return firstAndLast.split(" ")[1]} , this.getFullName= function(){ return firstAndLast;} , this.setFirstName= function(first){ firstAndLast=first+" "+firstAndLast.split(" ")[1]; } , this.setLastName= function(last){firstAndLast=firstAndLast.split(" ")[0]+" "+last; } , this.setFullName=function(full){ firstAndLast=full; } }; var bob = new Person('Bob Ross'); bob.getFullName();
轨道周期算法挑战
返回一个数组,其内容是把原数组中对应元素的平均海拔转换成其对应的轨道周期.
原数组中会包含格式化的对象内容,像这样 {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; var newArr = []; for(var i in arr){ period = Math.round(2 * Math.PI * Math.pow(Math.pow((earthRadius + arr[i].avgAlt), 3)/GM , 0.5)); newArr.push({name : arr[i].name , orbitalPeriod : period}); } return newArr; } orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
数据组合求值算法挑战:
找到你的另一半
都说优秀的程序员擅长面向对象编程,但却经常找不到另一半,这是为什么呢?因为你总是把自己局限成为一个程序员,没有打开自己的思维。
这是一个社群的时代啊,在这里你应该找到与你有相同价值观但又互补的另一半。
譬如:你编程能力强,估值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 |
任务:帮右边的pairwise函数实现上面的功能。
function pairwise(arr, arg) { var newArr = []; for (var i = 0; i < arr.length; i++) { var arrObj = {}; arrObj.num = i; arrObj.value = arr[i]; newArr.push(arrObj); } var count = 0; var arrLength = newArr.length; for (var j = 0; j < arrLength; j++) { for (var k = j + 1; k < arrLength; k++) { if (Number(newArr[j].value) + Number(newArr[k].value) == arg) { count = count + newArr[j].num + newArr[k].num; // console.log(count); newArr.splice(k,1); arrLength--; newArr.splice(j,1); arrLength--; j--; k-=2; break; } } } return count; } pairwise([1,4,2,3,0,5], 7);