初始思路:大寫字母ASCII範圍65-90,小寫字母ASCII範圍97-122,func_大寫轉小寫即爲val+32git
resultStr = '' for(str) { if (str[i] in 大寫字母ASCII碼範圍) { resultStr + = func_大寫轉小寫(str[i]) } else { resultStr += str[i] } } return resultStr
優化:
第一次優化:使用正則判斷字符是否處於大寫字母ASCII碼範圍,只有處於該範圍內才進行進行轉ASCII處理,結果複雜度不變,減小了轉換ASCII碼的次數。實現以下:數組
var toLowerCase = function(str) { let resultStr = ''; for (let i=0, strLen=str.length; i<strLen; i++) { let tempChar = str[i]; resultStr += /[A-Z]/.test(tempChar)? String.fromCharCode(tempChar.charCodeAt()+32) : tempChar; } return resultStr; };
實現:函數
var uniqueMorseRepresentations = function(words) { let morseArr = [".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."]; let set = new Set(); for (let i=0, wordsLen=words.length; i<wordsLen; i++) { let tempMorseStr = ''; for (let j=0, word=words[i]; j<word.length; j++) { tempMorseStr += morseArr[word[j].charCodeAt() - 97]; } set.add(tempMorseStr); } return set.size; };
初始思路:基於@分割,前面部分正則去點,而後取加號以前的部分,組合放入set去重;優化
實現ui
var numUniqueEmails = function(emails) { let set = new Set(); for (let i=0, emailsLen=emails.length; i<emailsLen; i++) { let tempArr = emails[i].split('@'); let localStr = tempArr[0]; localStr = localStr.replace(/\./g, ''); let indexAdd = localStr.indexOf('+'); if (indexAdd>-1) { localStr=localStr.slice(0, indexAdd); } set.add(localStr+'@'+tempArr[1]); } return set.size; };
首次優化:先基於加號分割再正則去點,組合操做一塊兒提升可讀性;spa
實現:code
var numUniqueEmails = function(emails) { let set = new Set(); for (let i=0, emailsLen=emails.length; i<emailsLen; i++) { let tempArr = emails[i].split('@'); let localStr = tempArr[0].split('+')[0].replace(/\./g, ''); set.add(localStr+'@'+tempArr[1]); } return set.size; };
初始思路:建立校驗函數,生成全部狀況的組合後逐個校驗;對象
優化:分析正確組合結果生成規律,只生成符合要求的結果;blog
左右括號規則(每次新增都有添加左括號和添加右括號兩種選擇,故重點在於瞭解不得添加狀況):排序
1 . 不可加左括號:左括號數量===Num 2 . 不可加右括號:首位、左右括號數量相等時
實現:
var generateParenthesis = function(n) { let arr = []; if (n===0) return []; calcFunc(arr, n, 0, 0, ''); return arr; }; function calcFunc(resultArr, N, leftNum, rightNum, currStr) { if (leftNum+rightNum === N*2) { resultArr.push(currStr); return; } if (leftNum !== N) { calcFunc(resultArr, N, leftNum+1, rightNum, currStr+'('); } if (currStr !== '' && leftNum !== rightNum) { calcFunc(resultArr, N, leftNum, rightNum+1, currStr+')'); } }
初始思路:放置兩個計數器,for字符串並增減計數器,最終計數器歸0則True;
實現:
var judgeCircle = function(moves) { let [x, y] = [0, 0]; for (let i=0, movesLen=moves.length; i<movesLen; i++) { if (moves[i] === 'L') { x++; } else if (moves[i] === 'R') { x--; } else if (moves[i] === 'U') { y++; } else if (moves[i] === 'D') { y--; } } return (x===0 && y===0)? true: false; };
思路二:使用Hashmap作須要字符數量的存儲,及最後用以對比
let map = new Map(); map.set('U', 0); map.set('D', 0); map.set('L', 0); map.set('R', 0); for (let i=0, movesLen=moves.length; i<movesLen; i++) { map.has(moves[i])? map.set(moves[i], map.get(moves[i])+1): ''; } return map.get('U')===map.get('D') && map.get('L')===map.get('R')
思路:首尾ij向中間推動並交換,i<j判斷失敗則退出
var reverseString = function(s) { let [i, j] = [0, s.length-1]; while (i<j) { [s[i], s[j]] = [s[j], s[i]] i++ j-- } return s };
初始思路:for words, 再for pattern.length, 當map不存在當前字母則添加,當map存在當前字母時比對,成功繼續,失敗next word
var findAndReplacePattern = function(words, pattern) { let resultArr = []; let patternLen = pattern.length; for(let i=0, wordsLen=words.length; i<wordsLen; i++) { let map = new Map(); let setVal = new Set(); let word = words[i]; let flag = true; for (let j=0; j<patternLen; j++) { if (map.has(pattern[j])) { if (map.get(pattern[j]) !== word[j]) { flag = false; break; } } else { map.set(pattern[j], word[j]); setVal.add(word[j]); if ( map.size!== setVal.size) { flag = false; break; } } } if (flag) { resultArr.push(word); } } return resultArr; };
圍觀:
實現:
var reverseWords = function(s) { let resultS = '' let arr = s.split(' ') for (let i=0, arrLen=arr.length; i<arrLen; i++) { resultS += arr[i].split('').reverse().join('') + ' ' } return resultS.trim() };
思路二:遍歷字符串並處理每段單詞(記錄開始位,遇到【下位爲空格or最後一位】記錄結束位&處理,處理完成後記錄結束位+2爲起始位),時間空間複雜度不變,減小了split('').reverse().join('')形成的空間損耗,實現以下:
var reverseWords = function(s) { let arr = s.split('') let [startIndex, endIndex] = [0, 0] for (let i=0, arrLen=arr.length; i<arrLen; i++) { if (arr[i+1]===' ' || i===arrLen-1) { endIndex = i reserveArr(arr, startIndex, endIndex) startIndex = i + 2 } } return arr.join('') }; function reserveArr (targetArr, sIndex, eIndex) { // console.log('[sIndex, eIndex]:', [sIndex, eIndex]) while (sIndex < eIndex) { [targetArr[sIndex], targetArr[eIndex]] = [targetArr[eIndex], targetArr[sIndex]] sIndex++ eIndex-- } }
思路:使用字符串分割或者正則提取輸入字符串的a和b值,計算得出結果a和b值,填充入模板字符串並返回
實現:
var complexNumberMultiply = function(a, b) { let [aArr, bArr] = [a.split('+'), b.split('+')] let [a1, b1] = [aArr[0], aArr[1].split('i')[0]] let [a2, b2] = [bArr[0], bArr[1].split('i')[0]] let [aResult, bResult] = [a1*a2-b1*b2, a1*b2+a2*b1] return `${aResult}+${bResult}i` }
實現:
var findLUSlength = function(a, b) { if (a === b) { return -1 } else { return Math.max(a.length, b.length) } };
思路一:暴力思路(不推薦)。切分S造成順序數組,並以此造成char+count的Map。for T並加入Map,for SArr按序造成結果字符串
實現:
var customSortString = function(S, T) { let orderArr = S.split('') let countMap = new Map() let resultS = '' for (let i=0, SLen=S.length; i<SLen; i++) { countMap.set(S[i], 0) } for (let i=0, TLen=T.length; i<TLen; i++) { if (countMap.has(T[i])) { countMap.set(T[i], countMap.get(T[i])+1) } else { countMap.set(T[i], 1) orderArr.push(T[i]) } } for (let i=0, orderArrLen=orderArr.length; i<orderArrLen; i++) { for (let j=0; j<countMap.get(orderArr[i]); j++) { resultS += orderArr[i] } } return resultS };
思路二:用Map存儲S順序,而後用數組存儲每一個S位置所對應的全部T字符,整合輸出
實現:
var customSortString = function(S, T) { let SLen = S.length let map = new Map() let resultArr = Array.from({length: SLen+1}, ()=>'') for (let i=0; i<SLen; i++) { map.set(S[i], i) } for (let i=0, TLen=T.length; i<TLen; i++) { if (map.has(T[i])) { resultArr[map.get(T[i])] += T[i] } else { resultArr[SLen] += T[i] } } return resultArr.join('') };
思路:for數組,取得item並將其分開爲奇字符串及偶字符串,sort兩個字符串並整合放入Set中,Set長度即結果。
實現
var numSpecialEquivGroups = function(A) { let set = new Set(); let itemSize = A[0].length; for (let i=0, ALen=A.length; i<ALen; i++) { let [oArr, eArr] = [[], []]; for (let j=0; j<itemSize; j++) { if (j%2===0) { eArr.push(A[i][j]) } else { oArr.push(A[i][j]) } } set.add(oArr.sort().join('')+eArr.sort().join('')); } return set.size; };
初始思路:枚舉0~9(間隔1)、10-90(間隔10)、100~900(間隔100)、1000-3000(間隔1000), 而後循環取數字最後一位取得對應字符串,累加結果。
實現:
var intToRoman = function(num) { let fixedArr = [ ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'], ['', 'M', 'MM', 'MMM'] ]; let resultStr = ''; let count = 0; while (num!==0) { resultStr = fixedArr[count++][num%10] + resultStr num = Math.floor(num/10) } return resultStr; };
優化思路:直接一路暴力if下來,免去了預先定義數組及從二維數組中取值,故速度空間都獲得節省。
實現:
var intToRoman = function(num) { let resultStr = '' if (num>=1000) { for (let i=0, len=Math.floor(num/1000); i<len; i++) { resultStr += 'M' } num = num%1000 } if (num>=900) { resultStr += 'CM' num -= 900 } if (num>=500) { resultStr += 'D' num -= 500 } if (num>=400) { resultStr += 'CD' num -= 400 } if (num>=100) { for (let i=0, len=Math.floor(num/100); i<len; i++) { resultStr += 'C' } num = num%100 } if (num>=90) { resultStr += 'XC' num -= 90 } if (num>=50) { resultStr += 'L' num -= 50 } if (num>=40) { resultStr += 'XL' num -= 40 } if (num>=10) { for (let i=0, len=Math.floor(num/10); i<len; i++) { resultStr += 'X' } num = num%10 } if (num>=9) { resultStr += 'IX' num -= 9 } if (num>=5) { resultStr += 'V' num -= 5 } if (num>=4) { resultStr += 'IV' num -= 4 } if (num>=1) { for (let i=0; i<num; i++) { resultStr += 'I' } } return resultStr; };
思路:建立對象映射單個羅馬數字與數值的關係,遍歷羅馬數字字符串,比較第 i 位與第 i+1 位的值,若是第 i 位的值小於第 i+1 位,則額外計算,其餘狀況直接計算得到結果。
實現:
var romanToInt = function(s) { let fixedObj = { '': 0, 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000 }; let result = 0; for (let i=0; i<s.length; i++) { if (s[i+1] && fixedObj[s[i+1]]>fixedObj[s[i]]) { result += fixedObj[s[i+1]] - fixedObj[s[i++]]; } else { result += fixedObj[s[i]]; } } return result; };
思路:編寫一個數字轉二進制字符串方法(避開32位限制),for 數組轉換結果,肯定是否在 S 中都存在。(因爲只要一個二進制字符串不匹配就退出故實際運行時間應該是更低的)
實現:
var queryString = function(S, N) { for (let i=0; i<=N; ++i) { if (S.indexOf(num2bin(i)) === -1) { return false; } } return true; }; function num2bin (num){ let binStr = ''; while(num>0) { binStr = num%2 + binStr; num = Math.floor(num/2); } return binStr; }
初始思路:遍歷數組,對item進行 sort 並做爲 map 的key,value 爲計數器的計數(也是結果數組的 index),根據map.has(key)的狀況,數組分別尾增新數組或在特定數組中尾插單詞。
實現:
var groupAnagrams = function(strs) { let map = new Map(); let resultArr = []; let count = 0; for (let i=0, arrLen=strs.length; i<arrLen; i++) { let tempStr = strs[i].split('').sort().join(''); if (map.has(tempStr)) { let index = map.get(tempStr); resultArr[index].push(strs[i]); } else { map.set(tempStr, count); resultArr[count++] = [strs[i]]; } } return resultArr; };
優化思路:用 map 存放 a-z 映射到26個質數的鍵值對,用每次"拆分 item 對得到乘積" 替換 "sort item"的過程
實現:
var groupAnagrams = function(strs) { var fixedObj={ a:2, b:3, c:5, d:7, e:11, f:13, g:17, h:19, i:23, j:29, k:31, l:37, m:41, n:43, o:47, p:53, q:59, r:61, s:67, t:71, u:73, v:79, w:83, x:89, y:97, z:101 } let map = new Map(); let resultArr = []; let count = 0; for (let i=0, arrLen=strs.length; i<arrLen; i++) { // let tempStr = strs[i].split('').sort().join(''); let uniqueNum = 1; for (let j=0, word=strs[i], len=word.length; j<len; j++) { uniqueNum *= fixedObj[word[j]]; } if (map.has(uniqueNum)) { let index = map.get(uniqueNum); resultArr[index].push(strs[i]); } else { map.set(uniqueNum, count); resultArr[count++] = [strs[i]]; } } return resultArr; };
題意解析:句子可被空格分割爲 n 個單詞,每一個單詞處理以下:
解題思路:按照題意編寫代碼
實現:
var toGoatLatin = function(S) { let arr = S.split(' '); for (let i=0, arrLen=arr.length; i<arrLen; i++) { if (/[aeiouAEIOU]/.test(arr[i][0])) { arr[i] += 'ma' } else { let tempArr = arr[i].split(''); tempArr = tempArr.splice(1, tempArr.length) tempArr.push(arr[i][0]) tempArr.push('ma') arr[i] = tempArr.join('') } for (let j=0, len=i+1; j<len; j++) { arr[i] += 'a' } } return arr.join(' ').trim() };
初始思路:建立 map,雙 for 循環組裝出實際文件路徑,並將內容做爲key,數組爲 value 放入 map, 相同數組不斷插入 value,最後取 map.values() 整合出目標二維數組。
實現:
var findDuplicate = function(paths) { let map = new Map(); for (let i=0, pathsLen=paths.length; i<pathsLen; i++) { let tempArr = paths[i].split(' '); let prefix = tempArr[0]; for (let j=1, len=tempArr.length; j<len; j++) { let fileArr = tempArr[j].split('('); let pathName = prefix + '/' + fileArr[0]; let content = fileArr[1].split(')')[0]; if (!map.has(content)) { map.set(content, []) } map.get(content).push(pathName) } } let resultArr = [] for (let value of map.values()) { if (value.length > 1) { resultArr.push(value) } } return resultArr };
優化思路:
優化點2:最後從 map.values()生產目標二維數組的過程使用 ES6語法的 Array.from + filter 代替,提升執行效率(反作用是加大內存消耗);
實現:
var findDuplicate = function(paths) { let map = new Map(); for (let i=0, pathsLen=paths.length; i<pathsLen; i++) { let tempArr = paths[i].split(' '); let prefix = tempArr[0]; for (let j=1, len=tempArr.length; j<len; j++) { let item = tempArr[j]; let contentIndex = item.indexOf('('); let content = item.slice(contentIndex+1, item.length-1); let pathName = prefix + '/' + item.slice(0, contentIndex); if (!map.has(content)) { map.set(content, []) } map.get(content).push(pathName) } } return Array.from(map.values()).filter(item=>item.length>1); };
初始解法:經過鍵值對方法,將每一個字符串的字母排序造成鍵,鍵相同的字符串放到一塊兒。
實現:
var groupAnagrams = function(strs) { let map = new Map(); for (let i=0, strsLen=strs.length; i<strsLen; i++) { let sortStr = strs[i].split('').sort().join('') if (map.has(sortStr)) { map.get(sortStr).push(strs[i]) } else { map.set(sortStr, [strs[i]]) } } return Array.from(map.values()); };
題意解析:計算 1-》N 中間的數字有多少個是好數,好數的定位爲180旋轉後仍爲數字且不與原數相等。即知足數字爲好數的前提是:
初始解法:全部數均爲有效=》沒有無效數字=》不包含(3,4,7), 故只要知足包含(2,5,6,9)且不包含(3,4,7)即符合要求,用正則能夠簡單得出結果。
實現:
var rotatedDigits = function(N) { let count = 0; for (let i=1, len=N+1; i<len; i++) { if (!(/[347]/g.test(i)) && /[2569]/g.test(i)) { count++; } } return count; };