前幾天逛 github 的時候看到一些前端的算法題,本身作了一遍發現還挺有意思的,所以整理了一下收錄 daily-question 的 algorithm 文件夾中,後續會繼續增長,本文分享我整理的十個算法題目。javascript
題外話:其實給這篇文章起名字的時候不知道起什麼名字,看了一些文章,整理了幾個模板:css
最後想一想仍是樸素一點,不作標題黨吧哈哈哈😜前端
題目描述:java
完成將 toChineseNum
, 能夠將數字轉換成中文大寫的表示,處理到萬級別,例如 toChineseNum(12345)
,返回 一萬二千三百四十五
。git
思路:程序員
對八位以上和一下進行分類討論:es6
getResult
方法處理八位數getResult
處理後在後面補'億'參考答案:github
function toChineseNum(num) { num += '' let numLength = num.length let numStr = '零一二三四五六七八九十' let unitArr = ['', '十', '百', '千', '萬'] function getResult(str) { let res = ''; if (str.length > 5) { let first = str.slice(-5); let second = str.slice(0, str.length - 5); for (let i in second) { res = res + numStr[second[i]] + unitArr[second.length - i]; } for (let i in first) { res = res + numStr[first[i]] + unitArr[first.length - i - 1]; } } else { let first = str.slice(-5); for (let i in first) { res = res + numStr[first[i]] + unitArr[first.length - i - 1]; } } res = res.replace(/零[零十百千]+/g, '零').replace(/零+$/g, '').replace(/零萬/g, '萬') return res; } if (numLength > 8) { return getResult(num.slice(0, numLength - 8)) + '億' + getResult(num.slice(-8)) } return getResult(num) } console.log(toChineseNum(1000005600454456))
題目描述:算法
完成函數 commafy
,它接受一個數字做爲參數,返回一個字符串,能夠把整數部分從右到左每三位數添加一個逗號,如:12000000.11
轉化爲 12,000,000.11
。數組
思路:
splice()
插入逗號參考答案:
function commafy (num) { let numStr = num + ''; let arr = num < 0 ? numStr.slice(1).split('.') : numStr.split('.'); let a = arr[0].split(''); // 整數部分切割成數組 for(let i = a.length - 3; i > 0; i=i-3) { a.splice(i, 0, ',') } let res = arr[1] ? a.join('') + '.' + arr[1] : a.join('') return num < 0 ? '-' + res : res; } console.log(commafy(12564654.456456)) // 12,564,654.456456
題目描述:
完成函數 hexToRGB,它的做用將 16 進制顏色值轉換成 RGB 值:
hexToRGB('#F0F0F0') // => rgb(240, 240, 240) hexToRGB('#9fc') // => rgb(153, 255, 204) hexToRGB('無效顏色') // => null
思路:
16 進制轉十進制如何計算。A,B,C,D,E,F,不區分大小寫這六個字母分別表示10,11,12,13,14,15 首先判斷是不是16進制的顏色,特色以#號開頭,其他是字母和數字,6位或者3位。 正則匹配如何只匹配3位數字或字母,或只匹配 6 位數字或字母
參考答案:
const hexToRGB = (hex) => { if (!/(^\#([a-fA-F0-9]{3})$)|(^\#([a-fA-F0-9]{6})$)/g.test(hex)) return null let allNumberStr = '0123456789abcdef' // 十六進制的全部數字 let len = hex.slice(1).length; let str = len === 6 ? hex.slice(1) : hex.slice(1)[0].repeat(2) + hex.slice(1)[1].repeat(2) + hex.slice(1)[2].repeat(2); let arrStr = str.split(''); let newArrStr = arrStr.map((item, index) => { return allNumberStr.indexOf((item + '').toLowerCase()) }) let num1 = newArrStr[0] * 16 + newArrStr[1]; let num2 = newArrStr[2] * 16 + newArrStr[3]; let num3 = newArrStr[4] * 16 + newArrStr[5]; return `rgb(${num1}, ${num2}, ${num3})` } console.log(hexToRGB('#fffaaa'))
題目描述:
小科去了一家新的公司作前端主管,發現裏面的前端代碼有一部分是 C/C++ 程序員寫的,他們喜歡用下劃線命名,例如: is_good。小科決定寫個腳原本所有替換掉這些變量名。
完成 toCamelCaseVar 函數,它能夠接受一個字符串做爲參數,能夠把相似於 is_good 這樣的變量名替換成 isGood。
思路:
replace()
實現參考答案:
const toCamelCaseVar = (variable) => { variable = variable.replace(/[\_|-](\w)/g, function (all, letter) { return letter.toUpperCase(); }); return variable.slice(0, 1).toLowerCase() + variable.slice(1) } console.log(toCamelCaseVar('Foo_style_css')) // fooStyleCss console.log(toCamelCaseVar('Foo-style-css')) // fooStyleCss
題目描述:
在前端的 MVVM
框架當中,咱們常常須要監聽數據的變化,而數組是須要監聽的重要對象。請你完成 ObserverableArray
,它的實例和普通的數組實例功能相同,可是當調用:push,pop,shift,unshift,splice,sort,reverse
這些方法的時候,除了執行相同的操做,還會把方法名打印出來。 例如:
const arr = new ObserverableArray() arr.push('Good') // => 打印 'push',a 變成了 ['Good']
注意,你不能修改 Array 的 prototype。還有函數 return 的值和原生的操做保持一致。
思路:
Proxy
監聽實現實現參考答案:
function ObserverableArray() { return new Proxy([], { get(target, propKey) { const matArr = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; matArr.indexOf(propKey) > -1 && console.log(propKey); return target[propKey] } }) } const arr = new ObserverableArray() arr.push('Good') // => 打印 'push',a 變成了 ['Good'] arr.push('Good2') // => 打印 'push',a 變成了 ['Good', 'Good2'] arr.unshift('Good2') // => 打印 'unshift',a 變成了 ['Good2','Good', 'Good2'] console.log(arr) // ['Good2','Good', 'Good2']
思路:
素數也稱爲質數,質數是指在大於1的天然數中,除了1和它自己之外再也不有其餘因數的天然數。有一下幾種狀況:
參考答案:
function isPrime(num){ if (typeof num !== 'number') { throw new TypeError('num should be number') } if (num === 2 || num === 3) { return true; }; if (num % 2 === 0) { return false; }; let divisor = 3, limit = Math.sqrt(num); while(limit >= divisor){ if (num % divisor === 0) { return false; } else { divisor += 2; } } return true; } console.log(isPrime(30)); // false console.log(isPrime(31)); // true
什麼是斐波那契數列:
斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖爲例子而引入,故又稱爲「兔子數列」,指的是這樣一個數列:一、一、二、三、五、八、1三、2一、3四、……在數學上,斐波那契數列以以下被以遞推的方法定義:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在現代物理、準晶體結構、化學等領域,斐波納契數列都有直接的應用,爲此,美國數學會從 1963 年起出版了以《斐波納契數列季刊》爲名的一份數學雜誌,用於專門刊載這方面的研究成果。
思路:
從上面的定義得出,斐波那契數列的三種狀況:
F(1)=1
F(2)=1
F(n)=F(n-1)+F(n-2)(n>=3,n∈N\*)
試用遞歸實現
function fibonacci(n) { if (n <= 0) { return 0; } if (n == 1) { return 1; } return fibonacci(n - 1) + fibonacci(n - 2); } console.time('fibonacci'); console.log(fibonacci(40)); // 102334155 console.timeEnd('fibonacci'); // 1106.791ms
仔細分析該遞歸,你會發現 f(40) = f(39) + f(38) , f(39) = f(38) + f(37) , f(38) = f(37) + f(36) , 算 f(40) 和 f(39) 都會計算 f(38),多算了一遍 f(38),會有明顯的效率問題。這種是從上至下計算(40-1),咱們換種思路,從下至上試試(1-40),首先根據 f(0)和 f(1)計算出 f(2),再根據 f(1)和 f(2)計算出 f(3)……以此類推就能夠計算出第 n 項。時間複雜度 O(n)。:
function fibonacci(n) { if (n <= 0) { return 0; } if (n == 1) { return 1; } let fiboOne = 1, fiboTwo = 0, fiboSum = 0; for (let i = 2; i <= n; i++) { fiboSum = fiboOne + fiboTwo; fiboTwo = fiboOne; fiboOne = fiboSum; } return fiboSum; } console.time('fibonacci'); console.log(fibonacci(40)); //102334155 console.timeEnd('fibonacci'); // 4.376ms
能夠看出,時間上少了將近 1000ms,數字越大,耗時差越大
參考答案:
function fibonacci(n) { if (n <= 0) { return 0; } if (n == 1) { return 1; } let fiboOne = 1, fiboTwo = 0, fiboSum = 0; for (let i = 2; i <= n; i++) { fiboSum = fiboOne + fiboTwo; fiboTwo = fiboOne; fiboOne = fiboSum; } return fiboSum; }
題目描述:
請你用 javascript 實現兩個字符串數字相加(大數相加)?
思路:
參考答案:
function add(a, b) { // 看看兩個字符串長度相差多少,小的在前面補0, 如 10000 和 1, 補0後爲 10000 和 00001 let leng = Math.abs(a.length - b.length); if (a.length > b.length) { b = Array(leng).join('0') + '0' + b; } else if (a.length < b.length) { a = Array(leng).join('0') + '0' + a; } // 將字符串轉化爲數組而且倒裝,如同小學加法從個位開始算起 let textArrA = a.split('').reverse(), textArrB = b.split('').reverse(), resultArr = []; // 對數組進行循環 for (let i = 0; i < a.length; i++) { // 求和,和小於10,則將和放進目標數組,若大於10,將除以10將餘數放進目標數組,而後textArrA數組的下一位 + 1(textArrB數組也能夠,選一個便可) let sum = parseInt(textArrA[i]) + parseInt(textArrB[i]); // 這裏判斷是不是最高位數值相加,即i === a.length - 1, 若是是不用取餘直接放進去 if (parseInt(sum / 10) === 0 || i === a.length - 1) { resultArr.push(sum); } else { resultArr.push(sum % 10); textArrA[i + 1] = parseInt(textArrA[i + 1]) + 1; } } // 最後將目標數組倒裝一下,再轉成字符串 return resultArr.reverse().join(''); } console.log(add('1045747', '10')); // 1045757
最大公約數:能同時被兩數整除的最大數字
最小公倍數:能同時整除兩數的最小數字
思路:
參考答案:
// 最大公約數 function maxDivisor(num1, num2) { let max = num1 > num2 ? num1 : num2, min = num1 > num2 ? num2 : num1; for (var i = min; i >= 1; i--) { if (max % i == 0 && min % i == 0) { return i; } } } console.log(maxDivisor(60, 30)); // 30 // 最小公倍數 function minDivisor(num1, num2) { let max = num1 > num2 ? num1 : num2, min = num1 > num2 ? num2 : num1, result = 0; // 這個循環,當兩數同爲質數時,終止的最大條件值爲 i = min for (var i = 1; i <= min; i++) { result = i * max; if (result % max == 0 && result % min == 0) { return result; } } } console.log(minDivisor(6, 8)); // 24
什麼是迴文?
迴文指從左往右和從右往左讀到相同內容的文字。好比: aba,abba,level。
思路:
function isPalindrome(str) { str = '' + str; if (!str || str.length < 2) { return false; } return ( Array.from(str) .reverse() .join('') === str ); }
function isPalindrome(str) { str = '' + str; if (!str || str.length < 2) { return false; } var newStr = ''; for (var i = str.length - 1; i >= 0; i--) { newStr += str[i]; } return str1 === str; }
return false
. 這種方法循環次數最少,效率最高function isPalindrome(str) { str = '' + str; if (!str || str.length < 2) { return false; } for (let i = 0; i < str.length / 2; i++) { if (str[i] !== str[str.length - 1 - i]) { return false; } } return true; }