leetcode 题目整理(一)

175 阅读9分钟

1. 两数之和

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  const hash = {}
  const n = nums.length
  for (let i = 0; i < n; i++) {
    const x = nums[i]
    if (hash[x] !== undefined) {
      return [hash[x], i]
    }
    hash[target - x] = i
  }
  return []
}

2. 两数相加

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function (l1, l2) {
  let head = new ListNode(-1)
  let cur = head
  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 = parseInt(sum / 10)
    sum %= 10
    cur.next = new ListNode(sum)
    cur = cur.next
  }
  return head.next
}

42. 接雨水

/**
 * 双指针
 * @param {number[]} height
 * @return {number}
 */
var trap = function (height) {
  let l = 0
  let r = height.length - 1
  let lHeight = 0
  let rHeight = 0
  let ans = 0
  while (l < r) {
    if (height[l] < height[r]) {
      lHeight = Math.max(lHeight, height[l])
      ans += lHeight - height[l]
      l++
    } else {
      rHeight = Math.max(rHeight, height[r])
      ans += rHeight - height[r]
      r--
    }
  }
  return ans
}
/**
 * 单调栈
 * @param {number[]} height
 * @return {number}
 */
var trap = function (height) {
  let ans = 0
  const stack = []
  for (let i = 0; i < height.length; i++) {
    while (stack.length && height[stack[stack.length - 1]] < height[i]) {
      const k = stack.pop()
      if (!stack.length) break
      const j = stack[stack.length - 1]
      const w = i - j - 1
      const h = Math.min(height[j], height[i]) - height[k]
      ans += h * w
    }
    stack.push(i)
  }
  return ans
}

3. 无重复字符的最长子串

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
  let set = new Set()
  let i = 0
  let j = 0
  let max = 0
  const n = s.length
  while (i < n) {
    const ch = s[i]
    while (set.has(ch)) {
      set.delete(s[j])
      j++
    }
    set.add(ch)
    max = Math.max(max, set.size)
    i++
  }
  return max
}

4. 寻找两个正序数组的中位数

var findMedianSortedArrays = function (nums1, nums2) {
  let n = nums1.length
  let m = nums2.length
  let len = n + m
  let mid = len >> 1
  let left = 0
  let right = 0
  let l = len % 2 === 0 ? mid - 1 : mid
  let r = mid
  let p1 = 0
  let p2 = 0
  let i = 0
  const check = (ans) => {
    if (i === l) {
      left = ans
    }
    if (i === r) {
      right = ans
    }
    i++
  }
  while (p1 < n && p2 < m && i <= r) {
    check(nums1[p1] < nums2[p2] ? nums1[p1++] : nums2[p2++])
  }
  while (p1 < n && i <= r) {
    check(nums1[p1++])
  }
  while (p2 < m && i <= r) {
    check(nums2[p2++])
  }
  return len % 2 ? left : (left + right) / 2
}

146. LRU 缓存


/**
 * @param {number} k
 * @param {number} v
 * @param {Node} l
 * @param {Node} r
 */
function Node(k, v, l, r) {
  this.l = l
  this.r = r
  this.k = k
  this.v = v
}
/**
 * @param {number} capacity
 */
var LRUCache = function (capacity) {
  this.size = capacity
  this.map = new Map()
  this.head = new Node(-1, -1)
  this.tail = new Node(-1, -1)
  this.head.r = this.tail
  this.tail.l = this.head
}

/**
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function (key) {
  const node = this.map.get(key)
  if (!node) return -1
  this.update(node)
  return node.v
}

/**
 * @param {Node} node
 * @return {void}
 */
LRUCache.prototype.update = function (node) {
  // 先从链表中提取出来
  this.delete(node)
  // 在头节点位置插入
  node.r = this.head.r
  node.l = this.head
  this.head.r.l = node
  this.head.r = node
}

/**
 * @param {Node} key
 * @return {void}
 */
LRUCache.prototype.delete = function (node) {
  if (node.l) {
    // 断开节点 1 -> 2 -> 3
    // 1 -> 3
    let l = node.l
    l.r = node.r
    node.r.l = l
  }
}

/**
 * @param {number} key
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function (key, value) {
  const node = this.map.get(key) || new Node(key, value)
  // 更新节点
  node.v = value
  this.map.set(key, node)
  // 更新位置
  this.update(node)
  if (this.map.size > this.size) {
    // 删除队尾元素
    let del = this.tail.l
    this.map.delete(del.k)
    this.delete(del)
  }
}

25. K 个一组翻转链表

var reverseKGroup = function(head, k) {
  const p = new ListNode(-1)
  p.next = head
  let prev = p
  while(head){
    let tail = prev
    for(let i = 0; i < k; i++){
      tail = tail.next
      if(!tail) return p.next
    }
    const next = tail.next;
    [head, tail] = reverse(head, tail)
    prev.next = head
    tail.next = next
    prev = tail
    head = tail.next
  }
  return p.next
};

var reverse = (head, tail) => {
  let prev = tail.next
  let p = head
  while(prev !== tail){
    const next = p.next
    p.next = prev
    prev = p
    p = next
  }
  return [tail, head]
}

5. 最长回文子串

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function (s) {
  let start = 0
  let end = 0
  const n = s.length
  for (let i = 0; i < n; i++) {
    const len1 = expand(s, i, i)
    const len2 = expand(s, i, i + 1)
    const len = Math.max(len1, len2)
    if (len > end - start) {
      start = i - Math.floor((len - 1) / 2)
      end = i + Math.floor(len / 2)
    }
  }
  return s.substring(start, end + 1)
}
const expand = (s, l, r) => {
  while (l >= 0 && r < s.length && s[l] === s[r]) {
    l--
    r++
  }
  return r - l - 1
}

206. 反转链表

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
  let prev = null
  while(head){
    const next = head.next
    head.next = prev
    prev = head
    head = next
  }
  return prev
};

7. 整数反转

/**
 * @param {number} x
 * @return {number}
 */
var reverse = function (x) {
  let res = 0
  while (x !== 0) {
    res = res * 10 + (x % 10)
    x = ~~(x / 10)
    if (res < Math.pow(-2, 31) || res > Math.pow(2, 31) - 1) {
      return 0
    }
  }
  return res
}

15. 三数之和

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
  let n = nums.length
  const res = []
  if (n < 2) return res
  nums.sort((a, b) => a - b)
  for (let i = 0; i < n - 2; i++) {
    const a = nums[i]
    if (a > 0) break
    if (i > 0 && a === nums[i - 1]) continue
    let l = i + 1
    let r = n - 1
    while (l < r) {
      const b = nums[l]
      const c = nums[r]
      const sum = a + b + c
      if (sum === 0) {
        res.push([a, b, c])
        while (l < r && b === nums[l + 1]) {
          l++
        }
        while (l < r && c === nums[r - 1]) {
          r--
        }
        l++
        r--
      } else if (sum > 0) {
        r--
      } else {
        l++
      }
    }
  }
  return res
}

440. 字典序的第K小数字

/**
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var findKthNumber = function (n, k) {
  let curr = 1
  k--
  while (k > 0) {
    const m = getMid(curr, n)
    if (m <= k) {
      k -= m
      curr++
    } else {
      curr = curr * 10
      k--
    }
  }
  return curr
}

var getMid = function (curr, n) {
  let m = 0
  let fast = curr
  let slow = curr
  while (fast <= n) {
    m += Math.min(slow, n) - fast + 1
    fast = fast * 10
    slow = slow * 10 + 9
  }
  return m
}

53. 最大子数组和

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function (nums) {
  // f(x) = max(f(x - 1) + f(x), f(x))
  const n = nums.length
  let pre = nums[0]
  let max = pre
  for (let i = 1; i < n; i++) {
    pre = Math.max(nums[i], pre + nums[i])
    max = Math.max(max, pre)
  }
  return max
}

11. 盛最多水的容器

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function (height) {
  let l = 0
  let r = height.length - 1
  let max = 0
  while (l < r) {
    max = Math.max(Math.min(height[l], height[r]) * (r - l), max)
    if (height[l] < height[r]) l++
    else r--
  }
  return max
}

124. 二叉树中的最大路径和

/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxPathSum = function (root) {
  let max = Number.MIN_SAFE_INTEGER
  const dfs = (node) => {
    if (!node) return 0
    const l = Math.max(dfs(node.left), 0)
    const r = Math.max(dfs(node.right), 0)
    const val = l + r + node.val
    max = Math.max(val, max)
    return node.val + Math.max(l, r)
  }
  dfs(root)
  return max
}

23. 合并K个升序链表

/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function (lists) {
  if (!lists.length) return null
  return toSortList(lists)
}

var toSortList = function (list) {
  if (list.length <= 1) return list[0]
  const mid = list.length >> 1
  return marge(mergeKLists(list.slice(0, mid)), mergeKLists(list.slice(mid)))
}

var marge = function (l1, l2) {
  if (!l1 && !l2) return null
  if (!l1 || !l2) return l1 || l2
  let curr = (head = new ListNode(null))
  while (l1 && l2) {
    if (l1.val < l2.val) {
      curr.next = l1
      l1 = l1.next
    } else {
      curr.next = l2
      l2 = l2.next
    }
    curr = curr.next
  }
  curr.next = l1 || l2
  return head.next
}

33. 搜索旋转排序数组

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function (nums, target) {
  let l = 0
  let r = nums.length - 1
  while (l <= r) {
    let m = l + Math.floor((r - l) / 2)
    if (nums[m] === target) return m
    if (nums[l] <= nums[m]) {
      if (nums[l] <= target && target < nums[m]) {
        r = m - 1
      } else {
        l = m + 1
      }
    } else {
      if (nums[m] < target && target <= nums[r]) {
        l = m + 1
      } else {
        r = m - 1
      }
    }
  }
  return -1
}

31. 下一个排列

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var nextPermutation = function (nums) {
  let i = nums.length - 2
  while (i >= 0 && nums[i] >= nums[i + 1]) {
    i--
  }
  if (i >= 0) {
    let j = nums.length - 1
    while (j >= 0 && nums[i] >= nums[j]) {
      j--
    }
    swap(nums, i, j)
  }
  // 反转后面的
  let l = i + 1
  let r = nums.length - 1
  while (l < r) {
    swap(nums, l++, r--)
  }
}
function swap(nums, i, j) {
  let temp = nums[i]
  nums[i] = nums[j]
  nums[j] = temp
}

56. 合并区间

/**
 * @param {number[][]} intervals
 * @return {number[][]}
 */
var merge = function (intervals) {
  intervals.sort((a, b) => a[0] - b[0])
  const n = intervals.length
  const res = []
  for (let i = 0; i < n; i++) {
    const l = intervals[i][0]
    const r = intervals[i][1]
    if (!res.length || res[res.length - 1][1] < l) {
      res.push([l, r])
    } else {
      res[res.length - 1][1] = Math.max(res[res.length - 1][1], r)
    }
  }
  return res
}

135. 分发糖果

/**
 * @param {number[]} ratings
 * @return {number}
 */
var candy = function (ratings) {
  const n = ratings.length
  const l = new Array(n).fill(1)
  const r = new Array(n).fill(1)
  for (let i = 1; i < n; i++) {
    if (ratings[i] > ratings[i - 1]) l[i] = l[i - 1] + 1
  }
  let count = l[n - 1]
  for (let i = n - 2; i >= 0; i--) {
    if (ratings[i] > ratings[i + 1]) r[i] = r[i + 1] + 1
    count += Math.max(l[i], r[i])
  }
  return count
}

92. 反转链表 II

/**
 * @param {ListNode} head
 * @param {number} left
 * @param {number} right
 * @return {ListNode}
 */
var reverseBetween = function (head, left, right) {
  const dummy = new ListNode()
  dummy.next = head
  let p = dummy
  let k = left - 1
  while (k--) p = p.next
  let front = p
  let pre = p.next
  let frontNode = pre
  let cur = pre.next
  k = right - left
  while (k--) {
    let next = cur.next
    cur.next = pre
    pre = cur
    cur = next
  }
  front.next = pre
  frontNode.next = cur
  return dummy.next
}

121. 买卖股票的最佳时机

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  const n = prices.length
  if (n < 2) return 0
  // 第 i 天 0 卖出, 1 持有
  // dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + p)
  // dp[i][1] = max(dp[i - 1][1], -p)
  const dp = new Array(n).fill(0).map(() => new Array(2).fill(0))
  dp[0][0] = 0
  dp[0][1] = -prices[0]
  for (let i = 1; i < n; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i])
    dp[i][1] = Math.max(dp[i - 1][1], -prices[i])
  }
  return dp[n - 1][0]
}
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  const n = prices.length
  // 最低的一天买进,最高的一天卖出
  let max = 0
  let min = Infinity
  for (let i = 0; i < n; i++) {
    min = Math.min(min, prices[i])
    max = Math.max(max, prices[i] - min)
  }
  return max
}

21. 合并两个有序链表

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var mergeTwoLists = function (l1, l2) {
  let head = new ListNode(null)
  let curr = head
  while (l1 && l2) {
    if (l1.val < l2.val) {
      curr.next = l1
      l1 = l1.next
    } else {
      curr.next = l2
      l2 = l2.next
    }
    curr = curr.next
  }
  curr.next = !l1 ? l2 : l1
  return head.next
}

199. 二叉树的右视图

/**
 * O(n) O(n)
 * @param {TreeNode} root
 * @return {number[]}
 */
var rightSideView = function (root) {
  if (!root) return []
  const q = [root]
  const result = []
  while (q.length) {
    const len = q.length
    let node = null
    for (let i = 0; i < len; i++) {
      node = q.shift()
      if (node.left) q.push(node.left)
      if (node.right) q.push(node.right)
    }
    result.push(node.val)
  }
  return result
}

215. 数组中的第K个最大元素

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var findKthLargest = function (nums, k) {
  return findK(nums, 0, nums.length - 1, nums.length - k)
}
var findK = function (nums, p, q, k) {
  if (p >= q) return nums[k]
  const m = partition(nums, p, q)
  return m > k ? findK(nums, p, m - 1, k) : findK(nums, m + 1, q, k)
}
var partition = function (nums, p, q) {
  const x = nums[p]
  let i = p + 1
  let j = q
  while (i < j) {
    while (i < j && nums[i] <= x) i++
    while (i < j && nums[j] >= x) j--
    swap(nums, i, j)
  }
  if (nums[j] >= x) j--
  swap(nums, j, p)
  return j
}
var swap = function (nums, i, j) {
  const tem = nums[i]
  nums[i] = nums[j]
  nums[j] = tem
}

70. 爬楼梯

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function (n) {
  // f(x) = f(x - 1) + f(x - 2)
  const dp = []
  dp[0] = 0
  dp[1] = 1
  dp[2] = 2
  for (let i = 3; i <= n; i++) {
    dp[i] = dp[i - 1] + dp[i - 2]
  }
  return dp[n]
}
/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function (n) {
  // f(x) = f(x - 1) + f(x - 2)
  let one = 1
  let two = 1
  for (let i = 2; i <= n; i++) {
    let temp = one + two
    one = two
    two = temp
  }
  return two
}

143. 重排链表

/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function (head) {
  let fast = head
  let slow = head
  while (fast.next && fast.next.next) {
    fast = fast.next.next
    slow = slow.next
  }
  let midHead = slow.next
  slow.next = null
  const s = []
  while (midHead) {
    s.push(midHead)
    const next = midHead.next
    midHead.next = null
    midHead = next
  }
  let cur = head
  while (cur) {
    const next = cur.next
    cur.next = s.pop() || null
    if (!cur.next) break
    cur.next.next = next
    cur = next
  }
  return head
}

/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function (head) {
  let fast = head
  let slow = head
  while (fast.next && fast.next.next) {
    fast = fast.next.next
    slow = slow.next
  }
  let p1 = head
  let p2 = reserve(slow.next)
  slow.next = null
  while (p2) {
    let n1 = p1.next
    let n2 = p2.next
    p1.next = p2
    p2.next = n1
    p1 = n1
    p2 = n2
  }
  return head
  function reserve(head) {
    let prev = null
    while (head) {
      const next = head.next
      head.next = prev
      prev = head
      head = next
    }
    return prev
  }
}

103. 二叉树的锯齿形层序遍历

/**
 * O(n) O(n)
 * @param {TreeNode} root
 * @return {number[][]}
 */
var zigzagLevelOrder = function (root) {
  const result = []
  if (!root) return result
  const stack = [root]
  let flag = true
  while (stack.length) {
    const res = []
    const len = stack.length
    for (let i = 0; i < len; i++) {
      const node = stack.shift()
      res.push(node.val)
      if (node.left) stack.push(node.left)
      if (node.right) stack.push(node.right)
    }
    if (!flag) res.reverse()
    flag = !flag
    result.push(res)
  }
  return result
}

46. 全排列

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function (nums) {
  const res = []
  const vis = {}
  const dfs = (t) => {
    if (t.length === nums.length) return res.push(t)
    for (const x of nums) {
      if (vis[x]) continue
      vis[x] = true
      t.push(x)
      dfs(t.slice())
      t.pop()
      vis[x] = false
    }
  }
  dfs([])
  return res
}

32. 最长有效括号

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
  const stack = [-1]
  const n = s.length
  let max = 0
  for (let i = 0; i < n; i++) {
    const c = s[i]
    if (c === '(') {
      stack.push(i)
    } else {
      stack.pop()
      if (stack.length <= 0) {
        stack.push(i)
      } else {
        max = Math.max(max, i - stack[stack.length - 1])
      }
    }
  }
  return max
}
/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
  let max = 0
  const n = s.length
  const dp = new Array(n).fill(0)
  for (let i = 1; i < n; i++) {
    if (s[i] === ')') {
      if (s[i - 1] === '(') {
        dp[i] = (dp[i - 2] || 0) + 2
      } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] === '(') {
        dp[i] = dp[i - 1] + (i - dp[i - 1] >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2
      }
      max = Math.max(dp[i], max)
    }
  }
  return max
}

54. 螺旋矩阵

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function (matrix) {
  const res = []
  const m = matrix.length
  const n = matrix[0].length
  const total = n * m
  let t = 0
  let b = m - 1
  let l = 0
  let r = n - 1
  while (res.length < total) {
    for (let i = l; i <= r; i++) res.push(matrix[t][i])
    t++
    for (let i = t; i <= b; i++) res.push(matrix[i][r])
    r--
    if (res.length >= total) break
    for (let i = r; i >= l; i--) res.push(matrix[b][i])
    b--
    for (let i = b; i >= t; i--) res.push(matrix[i][l])
    l++
  }
  return res
}

10. 正则表达式匹配

/**
 * @param {string} s
 * @param {string} p
 * @return {boolean}
 */
var isMatch = function (s, p) {
  const m = s.length
  const n = p.length
  const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(false))
  dp[0][0] = true
  for (let j = 1; j <= n; j++) {
    if (p[j - 1] === '*') dp[0][j] = dp[0][j - 2]
  }
  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (s[i - 1] === p[j - 1] || p[j - 1] === '.') {
        dp[i][j] = dp[i - 1][j - 1]
      } else if (p[j - 1] === '*') {
        if (s[i - 1] === p[j - 2] || p[j - 2] === '.') {
          dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 2] || dp[i - 1][j]
        } else {
          dp[i][j] = dp[i][j - 2]
        }
      }
    }
  }
  return dp[m][n]
}

22. 括号生成

/**
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesis = function (n) {
  const result = []
  const dfs = (s, l, r) => {
    if (l === 0 && r === 0) return result.push(s)
    if (l > 0) dfs(s + '(', l - 1, r)
    if (r > l) dfs(s + ')', l, r - 1)
  }
  dfs('', n, n)
  return result
}

148. 排序链表

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var sortList = function(head) {
  return toSortList(head, null)
};
/**
 * @param {ListNode} head
 * @param {ListNode} tail
 * @return {ListNode}
 */
var toSortList = function(head, tail) {
  if(!head) return head
  if(head.next === tail){
    head.next = null
    return head
  }
  const mid = findMidNode(head, tail)
  return marge(toSortList(head, mid), toSortList(mid, tail))
};

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
function marge(l1, l2){
  const dummy = new ListNode(null)
  let cur = dummy
  while(l1 && l2){
    if(l1.val < l2.val){
      cur.next = l1
      l1 = l1.next
    }else{
      cur.next = l2
      l2 = l2.next
    }
    cur = cur.next
  }
  cur.next = l1 || l2
  return dummy.next
}

/**
 * @param {ListNode} head
 * @param {ListNode} tail
 * @return {ListNode}
 */
var findMidNode = function(head, tail) {
  let fast = head
  let slow = head
  while(fast && fast !== tail) {
    slow = slow.next
    fast = fast.next
    if(fast && fast !== tail){
      fast = fast.next
    }
  }
  return slow
};

105. 从前序与中序遍历序列构造二叉树

/**
 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function (preorder, inorder) {
  const map = new Map()
  inorder.forEach((root, i) => map.set(root, i))
  const n = preorder.length
  const build = (pL, pR, iL, iR) => {
    if (pL > pR) return null
    const rootVal = preorder[pL]
    const root = new TreeNode(rootVal)
    const idx = map.get(rootVal)
    const leftSize = idx - iL
    root.left = build(pL + 1, pL + leftSize, iL, idx - 1)
    root.right = build(pL + leftSize + 1, pR, idx + 1, iR)
    return root
  }
  return build(0, n - 1, 0, n - 1)
}

200. 岛屿数量

/**
 * @param {character[][]} grid
 * @return {number}
 */
var numIslands = function (grid) {
  const dir = [
    [-1, 0],
    [0, -1],
    [1, 0],
    [0, 1],
  ]
  const m = grid.length
  const n = grid[0].length
  let ans = 0
  const dfs = (x, y) => {
    grid[x][y] = 1
    for (const [dx, dy] of dir) {
      const a = x + dx
      const b = y + dy
      if (a >= 0 && b >= 0 && a < m && b < n) {
        if (grid[a][b] === '1') {
          dfs(a, b)
        }
      }
    }
  }
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] === '1') {
        ans++
        dfs(i, j)
      }
    }
  }
  return ans
}

93. 复原 IP 地址

/**
 * @param {string} s
 * @return {string[]}
 */
var restoreIpAddresses = function (s) {
  const res = []
  const n = s.length
  const dfs = (t, start) => {
    if (start >= n && t.length === 4) return res.push(t.join('.'))
    if (t.length > 4) return
    for (let i = start; i < n; i++) {
      const str = s.slice(start, i + 1)
      if (str.length >= 2 && str[0] === '0') return
      if (str.length >= 3 && +str > 255) return
      t.push(str)
      dfs(t.slice(), i + 1)
      t.pop()
    }
  }
  dfs([], 0)
  return res
}

102. 二叉树的层序遍历

/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function (root) {
  if (!root) return []
  let res = []
  let q = [root]
  while (q.length) {
    let result = []
    let len = q.length
    for (let i = 0; i < len; i++) {
      let node = q.shift()
      if (!node) continue
      result.push(node.val)
      if (node.left) q.push(node.left)
      if (node.right) q.push(node.right)
    }
    res.push(result)
  }
  return res
}

41. 缺失的第一个正数

/**
 * @param {number[]} nums
 * @return {number}
 */
var firstMissingPositive = function (nums) {
  const n = nums.length
  for (let i = 0; i < n; i++) {
    if (nums[i] <= 0) {
      nums[i] = n + 1
    }
  }
  for (let i = 0; i < n; i++) {
    let num = Math.abs(nums[i])
    if (num <= n) {
      nums[num - 1] = -Math.abs(nums[num - 1])
    }
  }
  for (let i = 0; i < n; i++) {
    if (nums[i] > 0) {
      return i + 1
    }
  }
  return n + 1
}

20. 有效的括号

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
  if ((s.length & 1) == 1) return false
  const hash = {
    ')': '(',
    ']': '[',
    '}': '{',
  }
  const stack = []
  for (let i = 0; i < s.length; i++) {
    const ch = s[i]
    const k = hash[ch]
    if (k) {
      if (stack.pop() !== k) return false
    } else {
      stack.push(ch)
    }
  }
  return stack.length === 0
}

14. 最长公共前缀

/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
  const n = strs.length
  if (n === 1) return strs[0]
  let min = strs[0].length
  let T = strs[0]
  let index = 0
  for (let i = 1; i < n; i++) {
    if (strs[i].length < min) {
      min = strs[i].length
      T = strs[i]
      index = i
    }
  }
  let s = ''
  for (let i = 0; i < n; i++) {
    if (i === index) continue
    if (min === 0) return ''
    let l = 0
    let r = min
    let str = strs[i]
    s = ''
    while (l < r && T[l] === str[l]) {
      s += str[l]
      l++
    }
    min = l
    T = s
  }
  return s
}

72. 编辑距离

/**
 * @param {string} word1
 * @param {string} word2
 * @return {number}
 */
var minDistance = function (word1, word2) {
  const n = word1.length
  const m = word2.length
  const dp = new Array(n + 1).fill(0).map(() => new Array(m + 1).fill(0))
  for (let i = 0; i <= n; i++) {
    dp[i][0] = i
  }
  for (let i = 0; i <= m; i++) {
    dp[0][i] = i
  }
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= m; j++) {
      if (word1[i - 1] === word2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1]
      } else {
        dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1]) + 1
      }
    }
  }
  return dp[n][m]
}

198. 打家劫舍

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function (nums) {
  // f(x) = max(f(x - 2) + nums[x], f(x - 1))
  const dp = []
  dp[0] = nums[0]
  dp[1] = Math.max(nums[0], nums[1])
  const n = nums.length
  for (let i = 2; i < n; i++) {
    dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
  }
  return dp[n - 1]
}
/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function (nums) {
  // f(x) = max(f(x - 2) + nums[x], f(x - 1))
  const n = nums.length
  if (n === 1) return nums[0]
  let prev = nums[0]
  let curr = Math.max(nums[0], nums[1])
  for (let i = 2; i < n; i++) {
    let temp = Math.max(prev + nums[i], curr)
    prev = curr
    curr = temp
  }
  return curr
}

剑指 Offer 03. 数组中重复的数字

/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function (nums) {
  const n = nums.length
  let i = 0
  while (i < n) {
    if (nums[i] === i) {
      i++
    } else {
      if (nums[nums[i]] === nums[i]) return nums[i]
      const temp = nums[i]
      nums[i] = nums[nums[i]]
      nums[temp] = temp
    }
  }
}

剑指 Offer 09. 用两个栈实现队列

var MyQueue = function () {
  this.enqueue = []
  this.dequeue = []
}

/**
 * Push element x to the back of queue.
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function (x) {
  this.enqueue.push(x)
}

/**
 * Removes the element from in front of queue and returns that element.
 * @return {number}
 */
MyQueue.prototype.pop = function () {
  if (!this.dequeue.length) {
    while (this.enqueue.length) {
      this.dequeue.push(this.enqueue.pop())
    }
  }
  return this.dequeue.pop()
}

/**
 * Get the front element.
 * @return {number}
 */
MyQueue.prototype.peek = function () {
  if (!this.dequeue.length) {
    while (this.enqueue.length) {
      this.dequeue.push(this.enqueue.pop())
    }
  }
  return this.dequeue[this.dequeue.length - 1]
}

/**
 * Returns whether the queue is empty.
 * @return {boolean}
 */
MyQueue.prototype.empty = function () {
  return !this.dequeue.length && !this.enqueue.length
}

88. 合并两个有序数组

var merge = function (nums1, m, nums2, n) {
  let pos1 = m - 1
  let pos2 = n - 1
  let pos = m + n - 1
  while (pos1 >= 0 && pos2 >= 0) {
    nums1[pos--] = nums1[pos1] > nums2[pos2] ? nums1[pos1--] : nums2[pos2--]
  }
  if (pos1 == -1) {
    for (let i = 0; i < pos2 + 1; i++) {
      nums1[i] = nums2[i]
    }
  }
  return nums1
}

8. 字符串转换整数 (atoi)

const table = [
  [0, 1, 2, 3],
  [3, 3, 2, 3],
  [3, 3, 2, 3],
  [3, 3, 3, 3],
]

const num = {
  0: true,
  1: true,
  2: true,
  3: true,
  4: true,
  5: true,
  6: true,
  7: true,
  8: true,
  9: true,
}

class AutoMata {
  constructor() {
    this.state = 0
    this.sign = 1
    this.ans = 0
    this.max = Math.pow(2, 31) - 1
    this.min = -Math.pow(2, 31)
  }
  gets(c) {
    if (c == ' ') return 0
    if (c == '+' || c == '-') return 1
    if (num[c]) return 2
    return 3
  }
  get(c) {
    this.state = table[this.state][this.gets(c)]
    if (this.state == 2) {
      this.ans = this.ans * 10 + (c - 0)
      this.ans =
        this.sign == 1
          ? Math.min(this.ans, this.max)
          : Math.min(this.ans, -this.min)
    }
    if (this.state == 1 && c == '-') this.sign = -1
  }
}

const myAtoi = function (s) {
  const autoMata = new AutoMata()
  for (let i = 0; i < s.length; i++) {
    autoMata.get(s[i])
  }
  return autoMata.ans * autoMata.sign
}

128. 最长连续序列

var longestConsecutive = function (nums) {
  const n = nums.length
  if (!n) return 0
  const hash = {}
  let max = 1
  for (let i = 0; i < n; i++) hash[nums[i]] = true
  for (let i = 0; i < n; i++) {
    if (!hash[nums[i] - 1]) {
      let curr = nums[i] + 1
      let ans = 1
      while (hash[curr]) {
        ans++
        curr++
      }
      max = Math.max(max, ans)
    }
  }
  return max
}

13. 罗马数字转整数

var map = {
  I: 1,
  V: 5,
  X: 10,
  L: 50,
  C: 100,
  D: 500,
  M: 1000,
}
var romanToInt = function (s) {
  let last = 0
  let curr = 0
  for (let i = 0; i < s.length; i++) {
    let num = map[s[i]]
    if (num > last) {
      curr -= last
    } else {
      curr += last
    }
    last = num
  }
  return curr + last
}

24. 两两交换链表中的节点

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function (head) {
  const dummy = new ListNode(null, head)
  let cur = dummy.next
  let pre = dummy
  while (cur && cur.next) {
    let n = cur.next.next
    pre.next = cur.next
    cur.next = n
    pre.next.next = cur
    pre = cur
    cur = n
  }
  return dummy.next
}

var swapPairs = function (head) {
  if (!head || !head.next) return head
  let p = head.next
  head.next = swapPairs(p.next)
  p.next = head
  return p
}

76. 最小覆盖子串

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function (s, t) {
  let map = new Map()
  let hash = {}
  for (let ch of t) {
    hash[ch] = 0
    map.set(ch, (map.get(ch) || 0) + 1)
  }
  let l = 0
  let r = -1
  let check = () => {
    for (let [ch, count] of map.entries()) {
      if (hash[ch] < count) return false
    }
    return true
  }
  let len = Infinity
  let start = -1
  let end = -1
  while (r < s.length) {
    r++
    if (hash[s[r]] !== undefined) {
      hash[s[r]]++
    }
    while (l <= r && check()) {
      if (r - l + 1 < len) {
        len = r - l + 1
        start = l
        end = l + len
      }
      if (hash[s[l]]) {
        hash[s[l]]--
      }
      l++
    }
  }
  return s.substring(start, end)
}

739. 每日温度

var dailyTemperatures = function (T) {
  const stack = []
  const res = new Array(T.length).fill(0)
  for (let i = 0; i < T.length; i++) {
    while (stack.length && T[i] > T[stack[stack.length - 1]]) {
      const idx = stack.pop()
      res[idx] = i - idx
    }
    stack.push(i)
  }
  return res
}

69. x 的平方根

var mySqrt = function (x) {
  let left = 0
  let right = Math.floor(x / 2) + 1
  let ans = -1
  while (left <= right) {
    let mid = Math.floor((right + left) / 2)
    let num = mid * mid
    if (num < x) {
      ans = mid
      left = mid + 1
    } else if (num > x) {
      right = mid - 1
    } else {
      return mid
    }
  }
  return ans
}

221. 最大正方形

var maximalSquare = function (matrix) {
  const m = matrix.length
  const n = matrix[0].length
  const dp = new Array(m).fill(0).map(() => new Array(n).fill(0))
  let max = 0
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === '1') {
        if (i === 0 || j === 0) {
          dp[i][j] = 1
        } else {
          dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
        }
      }
      max = Math.max(dp[i][j], max)
    }
  }
  return max * max
}

9. 回文数

var isPalindrome = function (x) {
  if (x < 0 || (x % 10 === 0 && x !== 0)) return false
  let num = 0
  while (x > num) {
    let mod = x % 10
    num = num * 10 + mod
    x = Math.floor(x / 10)
  }
  return x === num || x === Math.floor(num / 10)
}

45. 跳跃游戏 II

var jump = function (nums) {
  let len = nums.length
  let end = 0
  let maxPosition = 0
  let steps = 0
  for (let i = 0; i < len - 1; i++) {
    maxPosition = Math.max(maxPosition, i + nums[i])
    if (i == end) {
      end = maxPosition
      steps++
    }
  }
  return steps
}

394. 字符串解码

/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function (s) {
  let res = ''
  for (let i = 0; i < s.length; ) {
    if (isNaN(s[i])) {
      res += s[i++]
    } else {
      let k = 0
      while (!isNaN(s[i])) {
        k = k * 10 + (s[i++] - 0)
      }
      let j = i + 1
      let sum = 1
      while (sum > 0) {
        if (s[j] === '[') sum++
        if (s[j] === ']') sum--
        j++
      }
      const r = decodeString(s.substring(i + 1, j - 1))
      while (k--) res += r
      i = j
    }
  }
  return res
}

51. N 皇后

/**
 * @param {number} n
 * @return {string[][]}
 */
var solveNQueens = function (n) {
  // 棋盘
  let grid = new Array(n).fill(0).map(() => new Array(n).fill('.'))
  // 是否同列
  let column = {}
  // 是否正对角线上存在
  let main = {}
  // 是否负对角线上存在
  let sub = {}
  // 记录路径
  let path = []
  // 剪枝方法
  let check = (x, y) => column[y] || main[x + y] || sub[x - y]
  // 深搜回溯
  let dfs = (t) => {
    // 如果到了第N行,证明找到一个解
    if (t == n) {
      path.push(grid.map((item) => item.join('')))
      return
    }
    for (let i = 0; i < n; i++) {
      // 每一行中都每一列尝试插入
      if (check(t, i)) continue
      // 记录状态
      grid[t][i] = 'Q'
      column[i] = main[t + i] = sub[t - i] = true
      dfs(t + 1)
      // 回溯
      column[i] = main[t + i] = sub[t - i] = false
      grid[t][i] = '.'
    }
  }
  dfs(0)
  return path
}

300. 最长递增子序列

/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function (nums) {
  if (!nums.length) return 0
  let dp = []
  dp[0] = 1
  let max = 1
  for (let i = 1; i < nums.length; i++) {
    dp[i] = 1
    for (let j = 0; j < i; j++) {
      if (nums[i] > nums[j]) {
        dp[i] = Math.max(dp[i], dp[j] + 1)
      }
    }
    max = Math.max(max, dp[i])
  }
  return max
}
// 动态规划 + 二分
var lengthOfLIS = function (nums) {
  let tail = []
  let res = 0
  for (let num of nums) {
    let i = 0,
      j = res
    while (i < j) {
      let m = Math.floor((i + j) / 2)
      if (num > tail[m]) i = m + 1
      else j = m
    }
    tail[i] = num
    if (j === res) res++
  }
  return res
}

剑指 Offer 51. 数组中的逆序对

/**
 * @param {number[]} nums
 * @return {number}
 */
var reversePairs = function (nums) {
  if (!nums.length) return 0
  return margeSort(nums, 0, nums.length - 1, [])
}
var margeSort = function (nums, l, r, result) {
  if (l >= r) return 0
  const m = (l + r) >> 1
  const lCount = margeSort(nums, l, m, result)
  const rCount = margeSort(nums, m + 1, r, result)
  const count = marge(nums, l, r, result)
  return count + lCount + rCount
}
var marge = function (nums, s, e, result) {
  let res = 0
  let e1 = (s + e) >> 1
  let s2 = e1 + 1
  let i1 = s
  let i2 = s2
  while (i1 <= e1 && i2 <= e) {
    if (nums[i1] <= nums[i2]) {
      result[i1 + i2 - s2] = nums[i1++]
    } else {
      result[i1 + i2 - s2] = nums[i2++]
      res += e1 - i1 + 1
    }
  }
  while (i1 <= e1) {
    result[i1 + i2 - s2] = nums[i1++]
  }
  while (i2 <= e) {
    result[i1 + i2 - s2] = nums[i2++]
  }
  while (s <= e) {
    nums[s] = result[s++]
  }
  return res
}

78. 子集

var subsets = function (nums) {
  let res = []
  let numLen = nums.length
  let dfs = (t, start) => {
    res.push(t)
    // 遍历开始
    for (let i = start; i < numLen; i++) {
      t.push(nums[i])
      dfs(t.slice(), i + 1)
      // 递归之后回溯
      t.pop()
    }
  }
  dfs([], 0)
  return res
}

var subset = function (nums) {
  let res = []
  let n = nums.length
  // 000 001 010 100 101 110 011 111
  let b = 1 << n
  for (let i = 0; i < b; i++) {
    let now = []
    for (let j = 0; j < n; j++) {
      if ((i >> j) & 1) {
        now.push(nums[j])
      }
    }
    res.push(now)
  }
  return res
}

79. 单词搜索

/**
 * @param {character[][]} board
 * @param {string} word
 * @return {boolean}
 */
var exist = function (board, word) {
  const m = board.length
  const n = board[0].length
  const dx = [-1, 0, 1, 0]
  const dy = [0, 1, 0, -1]
  const dfs = (x, y, len) => {
    if (len === word.length) return true
    const temp = board[x][y]
    board[x][y] = '#'
    for (let i = 0; i < 4; i++) {
      const a = x + dx[i]
      const b = y + dy[i]
      if (a >= 0 && b >= 0 && a < m && b < n && board[a][b] === word[len]) {
        if (dfs(a, b, len + 1)) return true
      }
    }
    board[x][y] = temp
    return false
  }
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (board[i][j] === word[0]) {
        if (dfs(i, j, 1)) return true
      }
    }
  }
  return false
}

101. 对称二叉树

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function (root) {
  return dfs(root.left, root.right)
}
var dfs = (left, right) => {
  if (!left && !right) return true
  if (!left || !right) return false
  if (left.val != right.val) return false
  return dfs(left.right, right.left) && dfs(left.left, right.right)
}

var isSymmetric = function (root) {
  if (!root || (root.left == root.right && root.right == null)) return true
  let q = [root.left, root.right]
  while (q.length) {
    let left = q.shift()
    let right = q.shift()
    if (!left && !right) continue
    if (!left || !right) return false
    if (left.val != right.val) return false
    q.push(left.left, right.right)
    q.push(left.right, right.left)
  }
  return true
}

415. 字符串相加

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var addStrings = function (num1, num2) {
  let i = num1.length - 1
  let j = num2.length - 1
  let carry = 0
  let res = ''
  while (i >= 0 || j >= 0 || carry) {
    let sum = carry
    if (i >= 0) {
      sum += +num1[i--]
    }
    if (j >= 0) {
      sum += +num2[j--]
    }
    carry = Math.floor(sum / 10)
    sum %= 10
    res = sum + res
  }
  return res
}

122. 买卖股票的最佳时机 II

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  // dp[i][0] 第 i 天卖出股票 dp[i][1] 第 i 天入手股票
  const n = prices.length
  const dp = new Array(n).fill(0).map(() => new Array(2).fill(0))
  dp[0][0] = 0
  dp[0][1] = -prices[0]
  for (let i = 1; i < n; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i])
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i])
  }
  return dp[n - 1][0]
}
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  // dp[i][0] 第 i 天卖出股票 dp[i][1] 第 i 天入手股票
  const n = prices.length
  let sell = 0
  let buy = -prices[0]
  for (let i = 1; i < n; i++) {
    let s = Math.max(sell, buy + prices[i])
    let b = Math.max(buy, sell - prices[i])
    sell = s
    buy = b
  }
  return sell
}
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  // 贪心,每次都卖
  let profit = 0
  for (let i = 1; i < prices.length; i++) {
    let temp = prices[i] - prices[i - 1]
    profit += temp > 0 ? temp : 0
  }
  return profit
}

6. Z 字形变换

/**
 * @param {string} s
 * @param {number} numRows
 * @return {string}
 */
var convert = function (s, numRows) {
  if (numRows === 1) return s
  let res = ''
  const n = s.length
  for (let j = 0; j < numRows; j++) {
    if (j === 0 || j === numRows - 1) {
      let i = j
      while (i < n) {
        res += s[i]
        i += 2 * (numRows - 1)
      }
    } else {
      let k = j
      let i = numRows * 2 - 1 - j - 1
      while (i < n || k < n) {
        if (k < n) res += s[k]
        if (i < n) res += s[i]
        i += 2 * (numRows - 1)
        k += 2 * (numRows - 1)
      }
    }
  }
  return res
}

剑指 Offer 11. 旋转数组的最小值

/**
 * @param {number[]} numbers
 * @return {number}
 */
var minArray = function (numbers) {
  let l = 0
  let r = numbers.length - 1
  while (l < r) {
    let m = l + ((r - l) >> 1)
    if (numbers[m] > numbers[r]) {
      l = m + 1
    } else if (numbers[m] < numbers[r]) {
      r = m
    } else {
      r--
    }
  }
  return numbers[l]
}

160. 相交链表

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function (headA, headB) {
  let p1 = headA
  let p2 = headB
  while (p1 != p2) {
    p1 = p1 == null ? headB : p1.next
    p2 = p2 == null ? headA : p2.next
  }
  return p1
}

543. 二叉树的直径

/**
 * @param {TreeNode} root
 * @return {number}
 */
var diameterOfBinaryTree = function (root) {
  let ans = 1
  var depth = function (root) {
    if (!root) return 0
    let left = depth(root.left)
    let right = depth(root.right)
    ans = Math.max(ans, left + right + 1)
    return Math.max(left, right) + 1
  }
  depth(root)
  return ans - 1
}

96. 不同的二叉搜索树

/**
 * @param {number} n
 * @return {number}
 */
var numTrees = function (n) {
  const dp = new Array(n + 1).fill(0)
  dp[0] = 1
  dp[1] = 1
  for (let i = 2; i <= n; i++) {
    for (let j = 1; j <= i; j++) {
      dp[i] += dp[j - 1] * dp[i - j]
    }
  }
  return dp[n]
}

236. 二叉树的最近公共祖先

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function (root, p, q) {
  let ans
  let dfs = (root, p, q) => {
    if (root == null) return false
    let left = dfs(root.left, p, q)
    let right = dfs(root.right, p, q)
    if (
      (left && right) ||
      ((root.val == p.val || root.val == q.val) && (left || right))
    ) {
      ans = root
    }
    return left || right || root.val == p.val || root.val == q.val
  }
  dfs(root, p, q)
  return ans
}
var lowestCommonAncestor = function (root, p, q) {
  if (!root || root == p || root == q) return root
  let left = lowestCommonAncestor(root.left, p, q)
  let right = lowestCommonAncestor(root.right, p, q)
  if (!left && !right) return null
  if (!left) return right
  if (!right) return left
  return root
}

剑指 Offer 22. 链表中倒数第k个

/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var getKthFromEnd = function (head, k) {
  if (k <= 0 || !head) return null
  let fast = head
  let slow = head
  while (k--) {
    fast = fast.next
  }
  while (fast) {
    fast = fast.next
    slow = slow.next
  }
  return slow
}

64. 最小路径和

/**
 * @param {number[][]} grid
 * @return {number}
 */
var minPathSum = function (grid) {
  const m = grid.length
  const n = grid[0].length
  for (let i = 1; i < m; i++) {
    grid[i][0] = grid[i - 1][0] + grid[i][0]
  }
  for (let i = 1; i < n; i++) {
    grid[0][i] = grid[0][i - 1] + grid[0][i]
  }
  for (let i = 1; i < m; i++) {
    for (let j = 1; j < n; j++) {
      grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]
    }
  }
  return grid[m - 1][n - 1]
}

104. 二叉树的最大深度

/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxDepth = function (root) {
  if (!root) return 0
  return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
}
var maxDepth = function (root) {
  if (!root) return 0
  let queue = [root]
  let ans = 0
  while (queue.length) {
    let count = queue.length
    while (count) {
      let node = queue.shift()
      if (node.left) queue.push(node.left)
      if (node.right) queue.push(node.right)
      count -= 1
    }
    ans += 1
  }
  return ans
}

224. 基本计算器

/**
 * @param {string} s
 * @return {number}
 */
var calculate = function (s) {
  let ops = [1]
  let sign = 1
  let n = s.length
  let i = 0
  let res = 0
  while (i < n) {
    const ch = s[i]
    if (ch == ' ') {
      i++
    } else if (ch == '+') {
      sign = ops[ops.length - 1]
      i++
    } else if (ch == '-') {
      sign = -ops[ops.length - 1]
      i++
    } else if (ch == '(') {
      ops.push(sign)
      i++
    } else if (ch == ')') {
      ops.pop()
      i++
    } else {
      let num = 0
      while (i < n && !isNaN(Number(s[i])) && s[i] != ' ') {
        num = num * 10 + s[i].charCodeAt() - '0'.charCodeAt()
        i++
      }
      res += sign * num
    }
  }
  return res
}

695. 岛屿的最大面积

/**
 * @param {number[][]} grid
 * @return {number}
 */
var maxAreaOfIsland = function (grid) {
  let dx = [-1, 0, 1, 0]
  let dy = [0, 1, 0, -1]
  let m = grid.length
  let n = grid[0].length
  let ans = 0
  let dfs = (x, y) => {
    grid[x][y] = 0
    let res = 1
    for (let i = 0; i < 4; i++) {
      let a = x + dx[i]
      let b = y + dy[i]
      if (a >= 0 && b >= 0 && a < m && b < n && grid[a][b] == 1) {
        res += dfs(a, b)
      }
    }
    return res
  }
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] == 1) {
        ans = Math.max(ans, dfs(i, j))
      }
    }
  }
  return ans
}

322. 零钱兑换

/**
 * @param {number[]} coins
 * @param {number} amount
 * @return {number}
 */
var coinChange = function (coins, amount) {
  const dp = new Array(amount + 1).fill(0)
  // f(X) = min(f(X-2)+1, f(X-5)+1, f(X-7)+1)
  for (let i = 1; i <= amount; i++) {
    let min = Number.MAX_SAFE_INTEGER
    for (const c of coins) {
      if (c <= i) {
        min = Math.min(min, dp[i - c] + 1)
      }
    }
    dp[i] = min
  }
  return dp[amount] === Number.MAX_SAFE_INTEGER ? -1 : dp[amount]
}

347. 前 K 个高频元素

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var topKFrequent = function (nums, k) {
  const map = new Map()
  const heap = new MinHeap(k, (a = {}, b = {}) => {
    return a.val <= b.val
  })
  const res = []
  nums.map((item) => {
    map.set(item, (map.get(item) || 0) + 1)
  })
  if (map.size <= k) {
    return [...map.keys()]
  }
  map.forEach((val, key) => {
    heap.add({ key, val })
  })
  while (heap.peek()) {
    res.push(heap.pop().key)
  }
  return res.reverse()
}

43. 字符串相乘

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var multiply = function (num1, num2) {
  if (num1 == '0' || num2 == '0') return '0'
  let res = '0'
  for (let i = num2.length - 1; i >= 0; i--) {
    let carry = 0
    let temp = new Array(num2.length - 1 - i).fill(0)
    let n2 = num2[i] - '0'
    for (let j = num1.length - 1; j >= 0 || carry != 0; j--) {
      let n1 = j < 0 ? 0 : num1[j] - 0
      let result = n1 * n2 + carry
      let product = result % 10
      temp.push(product)
      carry = Math.floor(result / 10)
    }
    res = addStrings(res, temp.reverse().join(''))
  }
  return res
}
let addStrings = (num1, num2) => {
  let carry = 0
  let res = []
  for (
    let i = num1.length - 1, j = num2.length - 1;
    i >= 0 || j >= 0 || carry != 0;
    i--, j--
  ) {
    let x = i < 0 ? 0 : num1[i] - 0
    let y = j < 0 ? 0 : num2[j] - 0
    let sum = x + y + carry
    res.push(sum % 10)
    carry = Math.floor(sum / 10)
  }
  return res.reverse().join('')
}

84. 柱状图中最大的矩形

/**
 * @param {number[]} heights
 * @return {number}
 */
var largestRectangleArea = function (heights) {
  heights.push(-1)
  const n = heights.length
  const stack = []
  let max = 0
  for (let i = 0; i < n; i++) {
    while (stack.length && heights[stack[stack.length - 1]] > heights[i]) {
      const cur = stack.pop()
      const j = !stack.length ? 0 : stack[stack.length - 1] + 1
      max = Math.max(max, heights[cur] * (i - j))
    }
    stack.push(i)
  }
  return max
}

134. 加油站

/**
 * @param {number[]} gas
 * @param {number[]} cost
 * @return {number}
 */
var canCompleteCircuit = function (gas, cost) {
  let n = gas.length
  for (let i = 0, j; i < n; i = i + j + 1) {
    let res = 0
    for (j = 0; j < n; j++) {
      let k = (i + j) % n
      res += gas[k] - cost[k]
      if (res < 0) break
    }
    if (j >= n) return i
  }
  return -1
}

98. 验证二叉搜索树

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isValidBST = function (root) {
  return isValid(root, -Infinity, Infinity)
}

var isValid = (root, lower, upper) => {
  if (!root) return true
  if (root.val <= lower || root.val >= upper) {
    return false
  }
  return (
    isValid(root.left, lower, root.val) && isValid(root.right, root.val, upper)
  )
}

85. 最大矩形

/**
 * @param {character[][]} matrix
 * @return {number}
 */
var maximalRectangle = function (matrix) {
  const m = matrix.length
  const n = matrix[0].length
  const left = new Array(m).fill(0).map(() => new Array(n).fill(0))
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === '1') {
        left[i][j] = (j === 0 ? 0 : left[i][j - 1]) + 1
      }
    }
  }
  let res = 0
  for (let j = 0; j < n; j++) {
    const up = new Array(m).fill(0)
    const down = new Array(m).fill(0)
    let stack = []
    for (let i = 0; i < m; i++) {
      while (stack.length && left[stack[stack.length - 1]][j] >= left[i][j]) {
        stack.pop()
      }
      up[i] = stack.length === 0 ? -1 : stack[stack.length - 1]
      stack.push(i)
    }
    stack = []
    for (let i = m - 1; i >= 0; i--) {
      while (stack.length && left[stack[stack.length - 1]][j] >= left[i][j]) {
        stack.pop()
      }
      down[i] = stack.length === 0 ? m : stack[stack.length - 1]
      stack.push(i)
    }
    for (let i = 0; i < m; i++) {
      const height = down[i] - up[i] - 1
      const area = height * left[i][j]
      res = Math.max(area, res)
    }
  }
  return res
}

240. 搜索二维矩阵 II

/**
 * @param {number[][]} matrix
 * @param {number} target
 * @return {boolean}
 */
var searchMatrix = function (matrix, target) {
  let m = matrix.length
  let n = matrix[0].length
  let row = m - 1
  let col = 0
  while (row >= 0 && col < n) {
    if (matrix[row][col] == target) return true
    else if (matrix[row][col] > target) {
      row--
    } else if (matrix[row][col] < target) {
      col++
    }
  }
  return false
}

19. 删除链表的倒数第 N 个结点

/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function (head, n) {
  const dummy = new ListNode(null, head)
  let p = dummy
  let q = dummy
  while (n--) {
    p = p.next
  }
  while (p.next) {
    p = p.next
    q = q.next
  }
  q.next = q.next.next
  return dummy.next
}

113. 路径总和 II

/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function (root, targetSum) {
  const result = []
  const dfs = (root, res, sum) => {
    if (!root) return
    sum -= root.val
    res.push(root.val)
    if (sum === 0 && !root.left && !root.right) return result.push(res.slice())
    dfs(root.left, res.slice(), sum)
    dfs(root.right, res.slice(), sum)
  }
  dfs(root, [], targetSum)
  return result
}

55. 跳跃游戏

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var canJump = function (nums) {
  let k = 0
  const n = nums.length
  for (let i = 0; i < n; i++) {
    if (i <= k) {
      k = Math.max(k, i + nums[i])
      if (k >= n - 1) {
        return true
      }
    }
  }
  return false
}

329. 矩阵中的最长递增路径

/**
 * @param {number[][]} matrix
 * @return {number}
 */
var longestIncreasingPath = function (matrix) {
  const dir = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1],
  ]
  const m = matrix.length
  const n = matrix[0].length
  const memo = new Array(m).fill(0).map(() => new Array(n).fill(0))
  let ans = 0
  const dfs = (x, y) => {
    if (memo[x][y] !== 0) return memo[x][y]
    ++memo[x][y]
    for (let [a, b] of dir) {
      a += x
      b += y
      if (a >= 0 && b >= 0 && a < m && b < n && matrix[a][b] > matrix[x][y]) {
        memo[x][y] = Math.max(memo[x][y], dfs(a, b) + 1)
      }
    }
    return memo[x][y]
  }
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      ans = Math.max(ans, dfs(i, j))
    }
  }
  return ans
}

297. 二叉树的序列化与反序列化

/**
 * Encodes a tree to a single string.
 *
 * @param {TreeNode} root
 * @return {string}
 */
var serialize = function (root) {
  if (!root) return '[]'
  let q = [root]
  let res = []
  while (q.length) {
    let node = q.shift()
    if (!node) res.push('#')
    else {
      res.push(node.val + '')
      q.push(node.left)
      q.push(node.right)
    }
  }
  return '[' + res.join(',') + ']'
}
/**
 * Decodes your encoded data to tree.
 *
 * @param {string} data
 * @return {TreeNode}
 */
var deserialize = function (data) {
  if (data == '[]') return null
  let values = data.substring(1, data.length - 1).split(',')
  let i = 0
  let root = new TreeNode(values[i++])
  let q = [root]
  while (q.length) {
    let node = q.shift()
    if (node) {
      let left = values[i++]
      let right = values[i++]
      node.left = left == '#' ? null : new TreeNode(left)
      node.right = right == '#' ? null : new TreeNode(right)
      q.push(node.left)
      q.push(node.right)
    }
  }
  return root
}

82. 删除排序链表中的重复元素 II

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var deleteDuplicates = function (head) {
  const dummy = new ListNode(null, head)
  let p = dummy
  while (p.next) {
    let q = p.next
    while (q && q.val == p.next.val) {
      q = q.next
    }
    if (q === p.next.next) p = p.next
    else p.next = q
  }
  return dummy.next
}

704. 二分查找

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
  let l = 0
  let r = nums.length - 1
  while(l < r){
    let m = l + ((r - l) >> 1)
    if(nums[m] >= target) r = m
    else l = m + 1
  }
  return nums[l] === target ? l : -1
};
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
  let l = 0
  let r = nums.length - 1
  while(l < r){
    let m = l + ((r - l + 1) >> 1)
    if(nums[m] <= target) l = m
    else r = m - 1
  }
  return nums[l] === target ? l : -1
};

剑指 Offer 38. 字符串的排列

/**
 * @param {string} s
 * @return {string[]}
 */
var permutation = function (s) {
  s = Array.from(s).sort()
  const res = []
  const n = s.length
  const vis = {}
  const dfs = (str) => {
    if (str.length === n) return res.push(str)
    for (let i = 0; i < n; i++) {
      if (i >= 1 && s[i] === s[i - 1] && !vis[i - 1]) continue
      if (vis[i]) continue
      vis[i] = true
      dfs(str + s[i])
      vis[i] = false
    }
  }
  dfs('')
  return res
}