初始思路:大写字母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; };