剛剛開始自學,網上很多相關帖子上來直接報上兩頁菜名成箫,初一看很有武俠小說里說書人的感覺.這本書怎樣怎樣展箱,那本書如何如何(本人文筆不行,可以自行腦補網絡小說各類比武橋段中龍?zhí)装l(fā)言)蹬昌。轉了一圈下來混驰,各類電子書下了不少,收藏夾也增長了幾頁皂贩。
真正學起來栖榨,才發(fā)現(xiàn)需要一個好的學習路徑和對應的代碼練習。其中代碼練習尤其地少明刷。有人也許會說婴栽,那么多代碼書,自己跟著敲一敲不就是練習么辈末,這還學不會愚争?刷題網站那么多,自己去刷題凹菲浮轰枝!
我打個比方,咱們都學過數(shù)學组去。除了那種看一看教材解釋鞍陨,就能完美理解的天才;兩個普通學生添怔,一個學習完數(shù)學定義及公式后湾戳,自己出題給自己做;一個則做各類教輔習題广料,這兩種情境下,學習效率絕對是天差地別的幼驶。再者艾杏,刷題網站的題目默認刷題者對語言已經學習完畢,重點在于對計算機原理及數(shù)學的應用盅藻。
綜上购桑,個人感覺freecodecamp對我這種半路自學的人還是有不少幫助的∈鲜纾花了一段時間勃蜘,按照它給的學習順序,從新手教程一直做到了高級算法題結束假残。在這里自己回顧一下之前自己的解法缭贡。
Validate US Telephone Numbers
檢查是否是美國電話號碼炉擅。其中有很多變體寫法,也要求返回正確阳惹。
function telephoneCheck(str) {
var a = str.match(/[0-9]/g).length;
var b = str.match(/^(?:(?:\(\d{3}\)|\d{3})[\s|-]?\d{3}[\s|-]?\d{4}$)/);
var c = str.match(/(?:\(\d{3}\)|\d{3})[\s|-]?\d{3}[\s|-]?\d{4}$/);
var d = str.match(/^1[^0-9]/);
if (a === 10 && b !== null) {
return true;
} else if (a === 11 && c !== null && d !== null) {
return true;
}
return false;
}
telephoneCheck("2 757 622-7382");
本來嘗試使用一個正則直接得出結果谍失,很可惜受限于水平原因,最后放棄了嘗試莹汤。
最后的代碼里面快鱼,通過a檢查傳入字符串中有多少個數(shù)字,在后面的if條件判斷中纲岭,分兩種情況(是否帶有國家代碼)來判斷抹竹。
值b用來匹配不帶國家代碼的電話號碼,前面的部分較后面來說比較復雜止潮。需要匹配三個數(shù)字及三個數(shù)字加括號這兩種情況窃判,但一邊單括號應當不能通過驗證。(?:(\d{3})|\d{3})這里沽翔,使用(?:)非捕獲括號兢孝,里面用 | 做了一個條件判斷,從而達到匹配三個數(shù)字或三個數(shù)字加括號這兩種情況仅偎。前面的用來防止匹配到帶國家代碼的電話(如果把b匹配放入if內跨蟹,可以去掉這個,因為已經通過a的數(shù)值判斷了是否帶國家代碼)橘沥。
值c和值b沒什么區(qū)別窗轩。
值d用來匹配國家代碼開頭部分(應該可以和c合并,當時只為通關也就沒改了)座咆。
Symmetric Difference
接受兩個或者多個數(shù)組痢艺。如果是兩個數(shù)組,互相判定差集介陶,把結果作為一個集合輸出堤舒。如果是多個數(shù)組,用上一次的結果作為其中一個數(shù)組哺呜,和下一個做相同的操作(就是reduce啦)舌缤。
function sym1(a, b) {
var c = [];
for (var i in a) {
if (b.indexOf(a[i]) === -1) {
c.push(a[i]);
}
}
for (var y in b) {
if (a.indexOf(b[y]) === -1) {
c.push(b[y]);
}
}
return c;
}
function sym(args) {
var d = [];
for (var i in arguments) {
d.push(arguments[i]);
}
var e = d.reduce(sym1);
var f = [e[0]];
for (var i = 1; i < e.length; i++) {
if (e[i] !== e[i - 1]) {
f.push(e[i]);
}
}
return f;
}
sym([1, 2, 3], [5, 2, 1, 4]);
先寫了一個reduce用的函數(shù)smy1。用indexOf判斷元素是否在集合中某残,如果不存在就放入準備好的結果容器c中国撵。
接下來在主函數(shù)中用for循環(huán)arguments取出輸入的所有數(shù)組,再使用reduce依次對等差分玻墅。注意這時如果輸入的數(shù)組中有多個重復的值介牙,而這個值滿足差分的要求,結果的數(shù)組中也會出現(xiàn)很多個相同的值澳厢。但是網站左側給出的例子要求我們不能出現(xiàn)重復环础,因此用一個for循環(huán)進行去重囚似。
Exact Change
寫一個收銀程序。
function checkCashRegister(price, cash, cid) {
var change;
var a = 0;
var b = [];
var e = cash - price;
var d = [0.01, 0.05, 0.10, 0.25, 1, 5, 10, 20, 100];
for (var i in cid) {
a += cid[i][1];
}
if ((cash - price) > a) {
return 'Insufficient Funds';
} else if ((cash - price) === a) {
return 'Closed';
}
for (var i = d.length - 1; i >= 0; i--) {
if (i === 0 && e <= cid[i][1]) {
b.push([cid[i][0], Math.round(e * 100) / 100]);
e = 0;
} else if (e >= d[i] && e <= cid[i][1] && cid[i][1] > 0) {
b.push([cid[i][0], Math.floor(e / d[i]) * d[i]]);
e = e - Math.floor(e / d[i]) * d[i];
} else if (e >= d[i] && e >= cid[i][1] && cid[i][1] > 0) {
b.push(cid[i]);
e = e - cid[i][1];
}
if (e === 0) {
break;
}
}
if (e !== 0) {
return 'Insufficient Funds';
}
return b;
}
sym([1, 2, 3], [5, 2, 1, 4]);
第一個for循環(huán)不用看喳整,出現(xiàn)的原因只是代碼通過了就沒改谆构。
第二個for循環(huán)是核心代碼。我的思路是用for循環(huán)對大面額到小面額依次進行判斷框都。每次會操作兩個變量搬素,一個是結果容器b(push進一個列表,包含面額魏保,和剩余金額)熬尺,一個是e(初始量是待找金額,每次循環(huán)如果面額和余額滿足要求谓罗,從e中扣除一定的錢)粱哼。如果循環(huán)中出現(xiàn)e=0的情況,用break語句跳出檩咱,因為此時找零已經完成揭措。如果直到循環(huán)結束,e仍有剩余刻蚯,說明錢找不開绊含。
感覺代碼還是亂炊汹,有修改的余地躬充。
Inventory Update
依照一個存著新進貨物的二維數(shù)組,更新存著現(xiàn)有庫存(在 arr1 中)的二維數(shù)組. 如果貨物已存在則更新數(shù)量 . 如果沒有對應貨物則把其加入到數(shù)組中讨便,更新最新的數(shù)量. 返回當前的庫存數(shù)組充甚,且按貨物名稱的字母順序排列。
function updateInventory(arr1, arr2) {
var a = [];
for (var i in arr1) {
a.push(arr1[i][1]);
}
for (var i in arr2) {
if (a.indexOf(arr2[i][1]) !== -1) {
arr1[a.indexOf(arr2[i][1])][0] += arr2[i][0];
} else {
arr1.push(arr2[i]);
}
}
arr1 = arr1.sort(function(a, b) {
return a[1].charCodeAt(0) - b[1].charCodeAt(0);
});
return arr1;
}
用for循環(huán)遍歷進貨霸褒,用indexOf判斷進貨中貨物名稱是否已經在庫存中存在伴找,如果存在就更新貨物數(shù)量,不存在則直接把這個數(shù)組加入庫存废菱。
按貨物名稱排序我直接用在sort內寫了一個匿名函數(shù)疆瑰,通過比較字母的ASCII大小排序。
No repeats please
把一個字符串中的字符重新排列生成新的字符串昙啄,返回新生成的字符串里沒有連續(xù)重復字符的字符串個數(shù).連續(xù)重復只以單個字符為準
例如, aab 應該返回 2 因為它總共有6中排列 (aab, aab, aba, aba, baa, baa), 但是只有兩個 (aba and aba)沒有連續(xù)重復的字符 (在本例中是 a).
function perms(str) {
var result = [];
var n = 0;
var m = str.length;
var perm = function(str, n, m) {
if (n === m - 1) {
result.push(str.join(''));
} else {
for (var i = n; i < m; i++) {
str[i] = [str[n], str[n] = str[i]][0];
perm(str, n + 1, m);
str[i] = [str[n], str[n] = str[i]][0];
}
}
};
perm(str, n, m);
return result;
}
function permAlone(str) {
var regex = /(.)\1+/g;
str = str.split('');
var b = perms(str);
var filter = b.filter(function(a) {
return ! a.match(regex);
});
return filter.length;
}
一開始當成一個數(shù)學題來做,想了很久寸五,發(fā)現(xiàn)其中要判斷的情況太多梳凛,寫出代碼要很多條件判斷。最后還是用全排列做了梳杏。
我的全排列函數(shù)perms是用遞歸做的韧拒。思路是淹接,有一個可用字符集合,取出其中一個叛溢,放在首位塑悼,接著更新這個字符集(集合中去除這個放在首位的字符),接著在新字符集中取出其中一個……不斷循環(huán)直至其中只有一個字符楷掉。在寫代碼的時候變了一下實現(xiàn)方式厢蒜,變成首字符和它后面的每一個字符依次交換,第二個字符和它后面的每一個字符依次交換烹植,直至遞歸出口(倒數(shù)第二個字符)斑鸦。
注意里面的匿名函數(shù)里的閉包情況(遞歸中每一次重新調用自身,并沒有創(chuàng)建一個新的變量草雕,它們都在操作同一個str巷屿,n,m墩虹。所以交換完了要再把str還原嘱巾。遞歸出口是把此時的str組裝成一個字符串。這個操作不僅有輸出格式上的考量诫钓,還有一個原因是旬昭,既然操作的都是同一個str,那么push進數(shù)組的當然也是同一個str尖坤,雖然它們身處數(shù)組稳懒,但一直在隨著函數(shù)里的str的變化而變化。所以我們需要把每次遞歸出口的str順序固定下來慢味,組裝字符串相當于創(chuàng)建了一個新的字符串對象场梆,從而達到固定順序的作用)。
Friendly Date Ranges
function makeDates(str) {
var arr = [];
str = str.split(/[^\d*]/);
for (var i in str) {
arr.push(parseInt(str[i], 10));
}
return arr;
}
function makeFriendlyDates(arr) {
var month = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
var days = [];
var array = [];
for (var z = 0; z < 31; z++) {
if (z >= 10 && z <= 20) {
days.push('th');
} else {
if (z % 10 === 1) {
days.push('st');
} else if (z % 10 === 2) {
days.push('nd');
} else if (z % 10 === 3) {
days.push('rd');
} else {
days.push('th');
}
}
}
for (var i in arr) {
array.push(makeDates(arr[i]));
}
var a = array[1][0] - array[0][0];
var b = array[1][1] - array[0][1];
var c = array[1][2] - array[0][2];
for (var y in array) {
array[y][0] = [array[y][2], array[y][2] = array[y][0]][0];
array[y][0] = [array[y][1], array[y][1] = array[y][0]][0];
replace(array[y]);
}
function replace(array) {
array[0] = month[array[0]];
array[1] = String(array[1]) + days[array[1]];
array[2] = String(array[2]);
if (array.length === 3) {
array[1] = array[1] + ',';
}
}
if (a * 360 + b * 30 + c >= 360) {} else if (a * 360 + b * 30 + c > 30 && array[0][2] === '2016') {
array[1] = array[1].splice(0, 2);
array[0] = array[0].splice(0, 2);
} else if (a * 360 + b * 30 + c > 30) {
array[1] = array[1].splice(0, 2);
array[0] = array[0].splice(0, 3);
} else if (a * 360 + b * 30 + c > 0) {
array[1] = [array[1][1]];
array[0] = array[0].splice(0, 2);
} else if (a === 0 && b === 0 && c === 0) {
array = [array[0]];
}
return array.map(function(a) {
return a.join(' ').replace(/,$/, '');
});
}
把一大堆條件判斷從人類語言轉換成代碼纯路。或油。。驰唬。顶岸。。叫编。這就是我寫這題的感覺辖佣,也許出題人的初衷不是這個?
Make a Person
var Person = function(name) {
var a = [name.split(' ')[0], name.split(' ')[1]];
this.getFirstName = function() {
return a[0];
};
this.getLastName = function() {
return a[1];
};
this.getFullName = function() {
return a[0] + ' ' + a[1];
};
this.setFirstName = function(b) {
a[0] = b;
};
this.setLastName = function(b) {
a[1] = b;
};
this.setFullName = function(b) {
a[0] = b.split(' ')[0];
a[1] = b.split(' ')[1];
};
};
var bob = new Person('Bob Ross');
bob.getFirstName();
匿名函數(shù)function(name)在類建立時就被調用搓逾,它用來建立一個類空間卷谈,其中的內容即是建立的類的內容。變量a用一個數(shù)組來儲存和修改Firstname及Lastname(把function(name)傳遞進類空間的name給spilt成兩塊)霞篡,給屬性賦予匿名函數(shù)世蔗,通過閉包操作變量a端逼。這六個函數(shù)大同小異,精簡成一個的話污淋,會非常簡潔顶滩,同時可以清晰地看到兩個要點。第一是通過函數(shù)建立類寸爆,第二是閉包的使用礁鲁。
Map the Debris
返回一個數(shù)組,其內容是把原數(shù)組中對應元素的平均海拔轉換成其對應的軌道周期.
function orbitalPeriod(arr) {
var GM = 398600.4418;
var earthRadius = 6367.4447;
function change(avgAlt) {
var r = earthRadius + avgAlt;
var b = Math.pow(r, 3) / GM;
var T = 2 * Math.PI * Math.pow(b, 0.5);
return Math.round(T);
}
var result = [];
for (var i in arr) {
var a = change(arr[i].avgAlt);
var dict = {};
dict.name = arr[i].name;
dict.orbitalPeriod = a;
result.push(dict);
}
return result;
}
用代碼把數(shù)學公式算一下而昨。外加一點點數(shù)據(jù)的取出救氯。不太清楚為什么要放在高級算法里。
Pairwise
舉個例子:有一個能力數(shù)組[7,9,11,13,15]歌憨,按照最佳組合值為20來計算着憨,只有7+13和9+11兩種組合。而7在數(shù)組的索引為0务嫡,13在數(shù)組的索引為3甲抖,9在數(shù)組的索引為1,11在數(shù)組的索引為2心铃。
所以我們說函數(shù):pairwise([7,9,11,13,15],20) 的返回值應該是0+3+1+2的和准谚,即6。
function pairwise(arr, arg) {
var count=0;
var red=[];
for(var i=0;i<arr.length;i++){
for(var y=i+1;y<arr.length;y++){
if(red.indexOf(i)!==-1||red.indexOf(y)!==-1){
continue;
}
else if(arr[i]+arr[y]===arg){
count+=i;
count+=y;
red.push(i);
red.push(y);
}
}
}
return count;
}
題目下面的提示是reduce去扣,我的思路里面沒有用到柱衔,自己嘗試用reduce想了一下,感覺有點阻力愉棱。
我的思路唆铐,遍歷每個值,每次遍歷中再對目前值之后的值進行一次遍歷奔滑。目的是每個值和它之后所有的值匹配艾岂,如果它們的和等于目標值,則把下標累加到變量count上朋其。題目中還有一個值得注意的點王浴,就是當兩個值匹配后,它們便不會和其他值匹配了梅猿。這里我通過一個變量red氓辣,作為一個池子,來儲存已經匹配過的變量的下標袱蚓。再循環(huán)中先進行條件判斷筛婉,若取出的值不在池中才進行下一步匹配(使用continue來實現(xiàn),continue:跳過次循環(huán)直接執(zhí)行下一次循環(huán),也可以使用一個if爽撒,判斷條件里用&&把“求和是否滿足要求”及“下標是否在池中”連起來)。