FCC參閱筆記之有趣的演算法(下)
收銀程式 checkCashRegister()
描述:設計一個收銀程式 checkCashRegister() ,其把購買價格(price)作為第一個引數 , 付款金額 (cash)作為第二個引數, 和收銀機中零錢 (cid) 作為第三個引數.
cid 是一個二維陣列,存著當前可用的找零.
當收銀機中的錢不夠找零時返回字串 “Insufficient Funds”. 如果正好則返回字串 “Closed”.
否則, 返回應找回的零錢列表,且由大到小存在二維陣列中.
解題程式:
function checkCashRegister(price, cash, cid) {
var balance = cash - price;
var change = [];
var unit = [100.00, 20.00, 10.00, 5.00, 1.00, 0.25, 0.10, 0.05, 0.01];//金額某面值的單位
//將給出的零錢陣列引數先反轉,然後對映其單位
var tempCid = cid.reverse().map(function(w,j){
w.push(unit[j]);
return w;
});
tempCid.forEach(function(v,i,arr){
if (v[1] > 0 && balance >= v[2 ]) {
if (balance >= v[1]) {
change.push([v[0], v[1]]);
//js減法的bug,可能會減出迴圈數值,在這裡使用toFixed()方法處理,然後將其轉為數值型別。
//balance為當前需要找的零錢數
balance = (balance - v[1]).toFixed(2) - 0;
//當前金額單位的剩餘數值
v[1] = 0;
} else {
//找出當前金額單位可以找零的數值
var tempMoney = parseInt (balance / v[2]) * v[2];
change.push([v[0], tempMoney]);
balance = (balance - tempMoney).toFixed(2) - 0;
v[1] -= tempMoney;
}
}
});
if (balance === 0) {
//通過判斷零錢陣列成員的第二個值是否為零判斷是否零錢數恰好為該找零的數值。
if (tempCid.every(function(v){return !v[1];})) {
return 'Closed';
}
//返回該找零的零錢陣列
return change;
} else if (balance > 0) {
return 'Insufficient Funds';
} else {
throw new Error('未知的錯誤');
}
}
Note:該題目為FCC的高階程式設計訓練題的某一個,題目並不很難,只是要對邊界條件、找零過程有一個清晰的思路。
FCC參考連結: 點選這裡
Inventory Update
描述: 依照一個存著新進貨物的二維陣列,更新存著現有庫存(在 arr1 中)的二維陣列. 如果貨物已存在則更新數量 . 如果沒有對應貨物則把其加入到陣列中,更新最新的數量. 返回當前的庫存陣列,且按貨物名稱的字母順序排列.
解題程式:
function updateInventory(arr1, arr2) {
var arr1key = arr1.map(function(v){
return v[1];
});
arr2.forEach(function(v){
if (arr1key.indexOf(v[1]) === -1) {
arr1.push(v);
} else {
arr1[arr1key.indexOf(v[1])][0] += v[0];
}
});
return arr1.sort(function(a,b){
return a[1].charCodeAt(0) - b[1].charCodeAt(0);
});
}
Note:該題目也比較簡單,在這裡寫出來,只是因為實現的思路挺好的,我們可以把第一個陣列成員的第一個元素單獨拎出來儲存起來,然後遍歷第二個陣列,判斷第二個陣列的當前成員的第一個屬性是否在我們儲存的屬性陣列中,然後使用indexOf()
方法找到他的位置,則這個位置也是該成員在第一個陣列中的位置。這樣方便了賦值操作。
FCC參考連結: 點選這裡
No repeats please
描述: 把一個字串中的字元重新排列生成新的字串(注:進行給定字串的全排列),返回新生成的字串裡沒有連續重複字元的字串個數.連續重複只以單個字元為準。例如, aab 應該返回 2 因為它總共有6中排列 (aab, aab, aba, aba, baa, baa), 但是隻有兩個 (aba and aba)沒有連續重複的字元 (在本例中是 a).
解題程式:
function permAlone(str) {
var strArr = str.split('');//將給定字串分割成陣列
//如果給定的字串是一個重複的元素,例:aaa,則直接返回0
if (strArr.every(function(v){return v === strArr[0];})) {
return 0;
}
var resultArr = [];
var tempArr = [];
var len = str.length;
//得到給定字串的全排列,使用遞迴實現。
(function rec(arr){
//對字串的最後一個元素的處理
if (arr.length === 1) {
var resultStrArr = tempArr.concat(arr);
//在這裡判斷該次的排列結果其元素是否有重複。
var bool = resultStrArr.some(function(v, i, arr) {
return v === arr[i + 1];
});
//如果不重複(例如:aba),將其壓入存入最終結果的陣列resultArr
if (!bool) {
resultArr.push(resultStrArr.join(''));
}
//丟擲倒數第二個陣列元素,方便下次迴圈時結果的存放
tempArr.pop();
} else {
//對給定遞迴陣列的一個深拷貝
var arr2 = arr.slice(0);
var len2 = arr2.length;
for (var i = 0;i <= len2; i++) {
if (i < len2) {
//push該次迴圈的元素
tempArr.push(arr2[i]);
//深拷貝一個新的迴圈陣列
var arr3 = arr2.slice(0);
//將已使用的元素從arr3中刪除
arr3.splice(i, 1);
//將處理後的arr3傳入rec函式,進行更深層次的遞迴操作
rec(arr3);
//如果該次陣列已結束迴圈,則對其存放該次排列結果的陣列進行pop操作。
} else {
tempArr.pop();
}
}
}
})(strArr);
//返回存入最終結果的陣列的長度。
return resultArr.length;
}
Note: 感覺這道題應該是FCC高階演算法程式設計題中最難的一個了,在網路上搜索了全排列的實現演算法,對其思路不怎麼理的很清楚,然而自己還是慢慢解出了這道題,感覺挺好的。這道題的難點在於對給定元素的全排列,首先要有遞迴實現的思路,其次在每次得到排列結果後需要對存放結果的陣列進行pop
操作,以存放下一次的迴圈的元素。
FCC參考連結: 點選這裡