JavaScript高階指令碼演算法程式設計練習(W3C學院)
JavaScript指令碼演算法程式設計實戰課程
目錄
1、判斷電話號碼演算法挑戰
如果傳入字串是一個有效的美國電話號碼,則返回 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) {
// Good luck!
var regExp1 = /^(1\s?)?\(\d{3}\)\s?\d{3}(\s|-)?\d{4}$/;
var regExp2 = /^(1\s)?\d{3}(\s|-)?\d{3}(\s|-)?\d{4}$/;
return (regExp1.test(str) || regExp2.test(str));
}
telephoneCheck("555-555-5555");
執行結果:true
2、集合交集演算法挑戰
建立一個函式,接受兩個或多個數組,返回所給陣列的 對等差分(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) { var arg = arguments; var newArgs = []; for(var i = 0; i < arguments.length; i++){ var newArg = []; for(var j = 0; j < arguments[i].length; j++){ if(arguments[i].indexOf(arguments[i][j]) == j){ newArg.push(arguments[i][j]); } } newArgs.push(newArg); } var returnArg = []; for(var k in newArgs){ for(var m in newArgs[k]){ if(returnArg.indexOf(newArgs[k][m]) == -1){ returnArg.push(newArgs[k][m]); }else{ returnArg.splice(returnArg.indexOf(newArgs[k][m]),1); } } } return returnArg; } sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
執行結果:[1,4,5]
3、 收銀系統演算法挑戰
設計一個收銀程式 checkCashRegister()
,其把購買價格(price
)作為第一個引數 , 付款金額 (cash
)作為第二個引數, 和收銀機中零錢 (cid
) 作為第三個引數。
cid
是一個二維陣列,存著當前可用的找零。
當收銀機中的錢不夠找零時返回字串 "Insufficient Funds"
. 如果正好則返回字串 "Closed"。
否者, 返回應找回的零錢列表,且由大到小存在二維陣列中
function checkCashRegister(price, cash, cid) {
var change = [];
var changeMoney = cash - price;
// console.log("要找回的總錢數:" + changeMoney);
// Here is your change, ma'am.
var cidDic = {
"ONE HUNDRED":100.00,
"TWENTY":20.00,
"TEN":10.00,
"FIVE":5.00,
"ONE":1.00,
"QUARTER":0.25,
"DIME":0.10,
"NICKEL":0.05,
"PENNY":0.01
};
var someMoney;//能找回的數量
for(var key in cidDic){
someMoney = 0;
while(changeMoney >= cidDic[key] && getSurplus(cid, key) >= cidDic[key]){
changeMoney = changeMoney - cidDic[key];//修改總數
someMoney += cidDic[key];
changeSurplus(cid, key, cidDic[key]);//修改收銀機中的零錢
}
if(someMoney !== 0){
change.push([key,someMoney]);
}
}
if(changeMoney === 0){
var flag = true;
for(var i in cid){
if(cid[i][1] !== 0){
flag = false;
break;
}
}
// console.log(flag);
if(flag){
return "Closed";
}else{
// console.log(change);
return change;
}
}else{
return "Insufficient Funds";
}
}
//根據第二個引數返回第一個引數中的值
function getSurplus(arr, key){
for(var i in arr){
if(arr[i][0] == key){
return arr[i][1];
}
}
}
//修改收銀機中的錢數
function changeSurplus(arr, key, val){
for(var i in arr){
if(arr[i][0] == key){
arr[i][1] =arr[i][1] - val;
}
}
}
// Example cash-in-drawer array:
// [["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]]
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]]);
執行結果:[["QUARTER",0.5]]
此題目設計到浮點數修正的問題,此處未作小數修正,解題思路是正確的。
4、庫存更新演算法挑戰
依照一個存著新進貨物的二維陣列,更新存著現有庫存(在 arr1
中)的二維陣列. 如果貨物已存在則更新數量 . 如果沒有對應貨物則把其加入到陣列中,更新最新的數量. 返回當前的庫存陣列,且按貨物名稱的字母順序排列.
function updateInventory(arr1, arr2) {
// All inventory must be accounted for or you're fired!
var flag;
for(var i in arr2){
flag = false;
for(var j in arr1){
if (arr2[i][1] == arr1[j][1]) {
flag = true;
break;
}
}
if(flag){
for(var k in arr1){
if(arr1[k][1] == arr2[i][1]){
arr1[k][0] += arr2[i][0];
}
}
}else{
arr1.push(arr2[i]);
}
}
var temp = [];
for(var m in arr1){
temp.push(arr1[m][1]);
}
temp.sort();
for(var n in temp){
for(var t in arr1){
if(temp[n] == arr1[t][1])
temp.splice(n,1,arr1[t]);
}
}
arr1 = temp;
return arr1;
}
// 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);
執行結果:[[88,"Bowling Ball"],[2,"Dirty Sock"],[3,"Hair Pin"],[3,"Half-Eaten Apple"],[5,"Microphone"],[7,"Toothpaste"]]
5、排列組合去重演算法挑戰
把一個字串中的字元重新排列生成新的字串,返回新生成的字串裡沒有連續重複字元的字串個數.連續重複只以單個字元為準
例如, aab
應該返回 2 因為它總共有6中排列 (aab
, aab
, aba
, aba
, baa
, baa
), 但是隻有兩個 (aba
and aba
)沒有連續重複的字元 (在本例中是 a
).
評論區5樓的程式碼是本題的一種方法,可以借鑑。
6、日期改寫演算法挑戰
讓日期區間更友好!
把常見的日期格式如: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) {
var startDate;
var endDate;
var times = new Date(arr[1]).getTime() - new Date(arr[0]).getTime();
// console.log(formatMonth(arr[0]));
//開始日期
if(new Date().getFullYear() == formatYear(arr[0]) && times > 0 && times < 365*24*60*60*1000){
startDate = formatMonth(arr[0]) + " " + formatDay(arr[0]);
}else{
startDate = formatMonth(arr[0]) + " " + formatDay(arr[0]) + ", " + formatYear(arr[0]);
}
//結束日期
if(formatMonth(arr[1]) == formatMonth(arr[0]) && formatYear(arr[0]) == formatYear(arr[1])){
endDate = "" + formatDay(arr[1]);
}else if((formatMonth(arr[1]) != formatMonth(arr[0]) || formatYear(arr[0]) != formatYear(arr[1])) && times > 0 && times < 365*24*60*60*1000){
endDate = formatMonth(arr[1]) + " " + formatDay(arr[1]);
}else{
endDate = formatMonth(arr[1]) + " " + formatDay(arr[1]) + ", " + formatYear(arr[1]);
}
arr[0] = startDate;
if(times === 0){
arr.splice(1,1);
}else{
arr[1] = endDate;
}
return arr;
}
function formatYear(_date){
return (new Date(_date)).getFullYear();
}
function formatDay(_date){
var _day = new Date(_date).getDate();
if (_day % 10 == 1 && _day != 11) {
_day = _day + "st";
} else if (_day % 10 == 2 && _day != 12) {
_day = _day + "nd";
} else if (_day % 10 == 3 && _day != 13) {
_day = _day + "rd";
} else {
_day = _day + "th";
}
return _day;
}
function formatMonth(_date){
var _month;
switch (new Date(_date).getMonth() + 1) {
case 1:
_month = "January";
break;
case 2:
_month = "February";
break;
case 3:
_month = "March";
break;
case 4:
_month = "April";
break;
case 5:
_month = "May";
break;
case 6:
_month = "June";
break;
case 7:
_month = "July";
break;
case 8:
_month = "August";
break;
case 9:
_month = "September";
break;
case 10:
_month = "October";
break;
case 11:
_month = "November";
break;
case 12:
_month = "December";
break;
}
return _month;
}
makeFriendlyDates(["2017-03-01", "2017-05-05"]);
執行結果:["March 1st, 2017","May 5th"]
7、類及物件構建演算法挑戰
用下面給定的方法構造一個物件.
方法有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(fullName){firstAndLast = fullName};
};
var bob = new Person('Bob Ross');
bob.getFullName();
執行結果:Bob Ross
8、 軌道週期演算法挑戰
返回一個數組,其內容是把原陣列中對應元素的平均海拔轉換成其對應的軌道週期.
原陣列中會包含格式化的物件內容,像這樣 {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: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]);
執行結果:
[{"name":"iss","orbitalPeriod":48815},{"name":"hubble","orbitalPeriod":50368},{"name":"moon","orbitalPeriod":20883321}]
9、資料組合求值演算法挑戰
找到你的另一半
都說優秀的程式設計師擅長面向物件程式設計,但卻經常找不到另一半,這是為什麼呢?因為你總是把自己侷限成為一個程式設計師,沒有開啟自己的思維。
這是一個社群的時代啊,在這裡你應該找到與你有相同價值觀但又互補的另一半。
譬如:你程式設計能力強,估值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, 3, 2, 4], 4);
執行結果:1