var maxArea = function(height) { let max = 0 let left = 0 let right = height.length - 1 while (left < right) { max = Math.max(max, Math.min(height[left], height[right]) * (right - left)) if (height[left] > height[right]) { right-- } else { left++ } } return max }
滑动窗口:维护一个合法区间
3. 无重复字符的最长子串(Medium)
找出字符串中不含重复字符的最长子串长度。
用左右两个指针维护一个无重复的窗口。右指针右移扩大窗口,遇到重复字符就左移收缩,直到窗口内无重复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var lengthOfLongestSubstring = function(s) { let left = 0, right = 0 let max = 0 const map = {} while (right < s.length) { if (map[s[right]] === undefined) { map[s[right]] = 1 right++ max = Math.max(max, right - left) } else { delete map[s[left]] left++ } } return max }
链表:模拟进位
2. 两数相加(Medium)
两个链表分别表示两个逆序整数,返回它们相加结果的链表。
按位相加,维护一个进位 carry。只要三者(l1、l2、carry)有一个不为 0,循环就继续。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
var addTwoNumbers = function(l1, l2) { const dummy = newListNode(0) let cur = dummy let carry = 0 while (l1 || l2 || carry) { let sum = carry if (l1) { sum += l1.val; l1 = l1.next } if (l2) { sum += l2.val; l2 = l2.next } carry = Math.floor(sum / 10) cur.next = newListNode(sum % 10) cur = cur.next } return dummy.next }
字符串:中心扩散 / 贪心 / 规律
5. 最长回文子串(Medium)
找出字符串中最长的回文子串。
中心扩散法:枚举每个字符作为回文中心,分奇偶两种情况向两边扩散,记录最长区间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var longestPalindrome = function(s) { let start = 0, end = 0 for (let i = 0; i < s.length; i++) { const len = Math.max(expand(s, i, i), expand(s, i, i + 1)) if (len > end - start) { start = i - Math.floor((len - 1) / 2) end = i + Math.floor(len / 2) } } return s.substring(start, end + 1) }
functionexpand(s, left, right) { while (left >= 0 && right < s.length && s[left] === s[right]) { left--; right++ } return right - left - 1 }
12 / 13. 罗马数字互转(Medium)
整数转罗马:贪心,维护一个从大到小的值表,每次尽量用最大的去减。
1 2 3 4 5 6 7 8 9 10 11 12
var intToRoman = function(num) { const values = [1000,900,500,400,100,90,50,40,10,9,5,4,1] const symbols = ['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'] let res = '' values.forEach((val, i) => { while (num >= val) { num -= val res += symbols[i] } }) return res }
罗马转整数:从左往右扫,当前字符比下一个小(如 IV 中的 I)就减,否则加。
1 2 3 4 5 6 7 8
var romanToInt = function(s) { const map = { M:1000, D:500, C:100, L:50, X:10, V:5, I:1 } let res = 0 for (let i = 0; i < s.length; i++) { map[s[i]] < map[s[i + 1]] ? res -= map[s[i]] : res += map[s[i]] } return res }
14. 最长公共前缀(Easy)
用 reduce 两两比较,每次求出当前公共前缀再和下一个对比:
1 2 3 4 5 6 7 8
var longestCommonPrefix = function(strs) { if (!strs.length) return'' return strs.reduce((pre, next) => { let i = 0 while (pre[i] && next[i] && pre[i] === next[i]) i++ return pre.slice(0, i) }) }
栈:括号匹配
20. 有效的括号(Easy)
判断括号字符串是否合法。
遇到左括号压栈,遇到右括号检查栈顶是否匹配。最后栈为空则合法。
1 2 3 4 5 6 7 8 9 10 11 12 13
var isValid = function(s) { if (s.length % 2 !== 0) returnfalse const map = { '(': ')', '[': ']', '{': '}' } const stack = [] for (const c of s) { if (map[c]) { stack.push(map[c]) } else { if (stack.pop() !== c) returnfalse } } return stack.length === 0 }