原文地址javascript
無心間發現 LeetCode 這個網站,一會兒就陷進去了,大學時候看舍友參加 acm 一天到晚刷題,對算法總有點特殊的情懷。本覺得我永遠是接觸不到這個了,沒想到 leetcode 卻讓我感受到 Accepted 這個單詞的特殊魅力。java
首先本身並非爲了找工做去刷題的,純粹享受作題的過程和ac的快感。題目所有用 JavaScript
作的,基本上天天一題的節奏。開始老是想着怎麼把答案解出來就好,常常 TLE ,感受一路作下來本身慢慢會考慮複雜度,邏輯嚴謹性也在逐步增強,對特殊值的考慮愈來愈多,相比於算法能力的提高我更欣喜看到本身邏輯嚴謹性增強,感受這對本身後面的道路幫助會很大。面試
這裏記錄本身對一些題目的思路和想法正則表達式
`算法
1 => true; 21 => false; 303 => true;
`json
數字迴文,說不能用額外的空間一會兒懵逼了,第一律念就是換成字符串比較,可是感受這樣子作就沒有意義了。看了別人思路發現給的數字每次取 10 的餘數拼起來正好是數字倒過來寫。若是隻取出一半,原數字也捨棄一半 正好就是迴文的兩個內容。有了思路就好作了判斷下特殊條件,比較最後兩個數字就能夠了,若是是奇數位數字就減掉中間一位再比較。數組
var max = Math.pow(2,31) - 1 var isPalindrome = function(x) { if (x < 0 || x > max || (x != 0 && x % 10 == 0)) return false if (x < 10) return true var num = 0 while(x > num) { num = num * 10 + x % 10 x = Math.floor(x / 10) } return num == x || (x != 0 && Math.floor(num / 10) == x) };
`函數
給定一個數組,想象成一個二位座標系,數組中每個元素 a[i] => n 就是座標系上的一條線段[ (i,0) => (i,x) ]。找出任意兩條線段與 x 軸組成的木桶,能夠盛水最大的值。
`網站
看到題目想了一下就想着兩層循環去計算,果真就超時了,看了看別人的思路,開始就算出0到最後一個線段組成的木桶的面積,而後找出線段比較短的一條向中間靠攏,若是下一條線段比當前線段還短就忽略,反之就繼續循環計算。想了想這樣作也是合理的若是下一條線段比當前的還短那組成的面積確定比較小。有了思路就好作了spa
var maxArea = function(height) { let i = 0, l = height.length -1, res = 0 while(i < l) { var h = Math.min(height[i],height[l]) res = Math.max(res, (l-i) * h) if(height[i] < height[l]) { while(height[i] <= h && i < l){i++} } else { while(h >= height[l] && i < l){l--} } } return res }
`
實現正則, '.' Matches any single character. '*' Matches zero or more of the preceding element. isMatch("aa","a") → false isMatch("ab", ".*") → true isMatch("aab", "c*a*b") → true
`
剛開始看到這題目仍是比較懵的,感受要判斷的好多,後面從遞歸判斷作就有思路了,從正則表達式入手,先判斷第二位是否是 * ,若是不是就判斷第一位而後截取一位遞歸,若是是就先去除正則前兩位遞歸,不行再判斷第一個是否是相等而後循環遞歸
var isMatch = function(s, p) { if(p[0] === undefined) return s[0] === undefined if (p[1] != '*') { if (s[0] === p[0] || (p[0] === '.' && s[0] !== undefined)) return isMatch(s.substr(1), p.substr(1)) else return false } else { if (isMatch(s, p.substr(2)))return true let index = 0 while(index <= s.length && (s[index] === p[0] || p[0] === '.')){ if(isMatch(s.substr(++index), p.substr(2))) return true } return false } }
看到一個面試題,JSON.stringify 是 javascript
的一個方法返回一個json格式的字符串,效果以下
const obj = {a:1, b:2} JSON.stringify(obj) // => '{"a":1,"b":2}'
當要轉化的對象有「環」存在時(子節點屬性賦值了父節點的引用),爲了不死循環,JSON.stringify 會拋出異常,例如:
var a = [1] a.push(a) JSON.stringify(a) // => Uncaught TypeError: Converting circular structure to JSON
寫一個函數判斷參數是否包含 環
,本身想到的是用 map
對象把是對象的值作爲鍵存儲值,而後判斷值是否存在來判斷是否迴環, 要注意每一次要用一個新的 map 對象,避免同級別相互引用判斷錯誤的狀況
let isCircular = (o) => { var flag = false const func = (obj, map = new Map()) => { map.set(obj, true) Object.values(obj).forEach(d=> { if (flag) return if (typeof d == 'object') { if (map.get(d)) { flag = true return } else { let newmap = new Map(map) func(d, newmap) } } }) } func(o) return flag }
給一個數字,寫一個函數根據數字生成全部形式良好的括號組合 2 => ["()()", "(())"] 3 => [ "((()))", "(()())", "(())()", "()(())", "()()()" ]
想了一下有一個思路,就是根據 ()
裏面的包含幾個子 ()
來得出全部狀況。 好比給出的數字是5, 那麼循環到5,第n 就有 ( [func(n)的結果] )
* func(4-n)的結果
。
一直想着以一個優雅的方式處理邊界的問題,可是想半天都沒結果,只能寫的醜陋點了。
var generateParenthesis = function(n) { if(n == 0) return [] if(n == 1) return ['()'] let arr = [] for(let i = 0; i < n; i++) { if( i == 0) { arr = arr.concat(generateParenthesis([n-1]).map(d => '()' + d )) } else if (i == n-1){ arr = arr.concat(generateParenthesis([n-1]).map(d => '(' + d + ')')) } else { generateParenthesis(i).forEach(d => { let eachres = '(' + d +')' generateParenthesis(n- i -1).forEach(c => { arr.push(eachres + c) }) }) } } return arr };