[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_size = 2\nindent_style = space\n\n[*.py]\nindent_size = 4\n\n[*.{md,markdown}]\nindent_size = 4\n\n[Makefile]\nindent_style = tab\n"
  },
  {
    "path": ".gitignore",
    "content": "__pycache__\nnode_modules\n*-lock.json\n"
  },
  {
    "path": ".travis.yml",
    "content": "matrix:\n  include:\n    - language: python\n      python: \"3.6\"\n      script:\n        - $TRAVIS_BUILD_DIR/bin/test_python.py\n    - language: node_js\n      node_js:\n        - \"lts/carbon\"\n      before_script:\n        - npm install -g jest\n      script: jest --config=$TRAVIS_BUILD_DIR/bin/test_javascript.js\n"
  },
  {
    "path": "README.md",
    "content": "Algorithm\n======\n\n[![Build Status](https://travis-ci.org/jaychsu/algorithm.svg?branch=master)](https://travis-ci.org/jaychsu/algorithm)\n\nThe challenges for algorithm contests, and summary the implementation.\n\n## Structure\n\n| Top-level Folder | Note |\n| :--- | :--- |\n| bin | commands |\n| topic | implementation and summaries of algorithms and data structures |\n| other | for problems met in life |\n| codeforces | for [Codeforces](http://codeforces.com) |\n| codejam | for [PastContests](https://code.google.com/codejam/past-contests) in [code jam](https://code.google.com/codejam) from Google |\n| codelab | for [Code Lab](https://codelab.interviewbit.com) from Facebook |\n| codewars | for [Codewars](https://www.codewars.com) |\n| geeksforgeeks | for [GeeksforGeeks](https://www.geeksforgeeks.org) |\n| hackerrank | for [HackerRank](https://www.hackerrank.com/contests) |\n| leetcode | for [LeetCode](https://leetcode.com) |\n| lintcode | for [LintCode](http://www.lintcode.com) |\n| pramp | for [Pramp](https://www.pramp.com) |\n| topcoder | for [ActiveContests](https://community.topcoder.com/longcontest/?module=ViewActiveContests), [Practices](https://community.topcoder.com/longcontest/?module=ViewPractice), and [ProblemArchives](https://community.topcoder.com/tc?module=ProblemArchive) in [Topcoder](https://www.topcoder.com) |\n| Scaler | for [Scaler Topics](https://www.scaler.com/topics/) |\n| InterviewBit | for [Technical Interview](https://www.interviewbit.com/technical-interview-questions/), [Data Structures and Algorithms](https://www.interviewbit.com/courses/programming/), [Contests](https://www.interviewbit.com/contests/), and [Mock Interviews](https://www.interviewbit.com/mock-interview/) |\n\n## Testing\n\n| Language | Command |\n| :--- | :--- |\n| Python | [./bin/test_python.py](./bin/test_python.py) |\n| Javascript | |\n"
  },
  {
    "path": "bin/test_javascript.js",
    "content": "// TODO: wrap this file to a executable command\n// [Configuring Jest](https://facebook.github.io/jest/docs/en/configuration.html)\n\n\nmodule.exports = {\n  \"rootDir\": \"..\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \"/(other|topic)/.*(\\\\.|/)(test|spec)\\\\.jsx?$\",\n  \"verbose\": true,\n}\n"
  },
  {
    "path": "bin/test_python.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\nimport os\nimport sys\nimport unittest\nimport doctest\n\nsys.path.append(os.path.join(\n    os.path.dirname(__file__),\n    '../topic'\n))\nfrom _test.python.test_base import TaskTimer\n\n\ndef get_unittests(dirname):\n    ROOT_DIR = os.path.join(\n        os.path.dirname(__file__),\n        '../{dirname}'.format(dirname=dirname)\n    )\n    tests = []\n\n    for path, _, files in os.walk(ROOT_DIR):\n        if ('pycache' in path or\n            'python' not in path or\n            '__init__.py' not in files):\n            continue\n\n        tests.append(unittest.defaultTestLoader.discover(\n            path,\n            pattern='*__test.py',\n            top_level_dir=ROOT_DIR\n        ))\n\n    return tests\n\n\ndef get_doctests(dirname):\n    ROOT_DIR = os.path.join(\n        os.path.dirname(__file__),\n        '../{dirname}'.format(dirname=dirname)\n    )\n    tests = []\n    sys.path.append(ROOT_DIR)\n\n    for path, _, files in os.walk(ROOT_DIR):\n        if 'pycache' in path:\n            continue\n\n        for file in files:\n            if (file.startswith('_') or\n                not file.endswith('.py')):\n                continue\n\n            timer = TaskTimer()\n            tests.append(doctest.DocTestSuite(\n                file[:-3],\n                setUp=lambda globs: timer.reset_time(),\n                tearDown=lambda globs: timer.print_duration()\n            ))\n\n    sys.path.pop()\n    return tests\n\n\nif __name__ == '__main__':\n    suite = unittest.TestSuite()\n\n    for tests in (\n        get_unittests('topic'),\n        get_doctests('leetcode'),\n        get_doctests('pramp'),\n        get_doctests('other'),\n    ):\n        suite.addTests(tests)\n\n    unittest.TextTestRunner(verbosity=2).run(suite)\n"
  },
  {
    "path": "codewars/delete_occurrences_of_an_element_if_it_occurs_more_than_n_times.js",
    "content": "function deleteNth(nums, n) {\n  const freq = {}\n\n  for (let i = 0; i < nums.length; i++) {\n    const num = nums[i]\n\n    if (!freq.hasOwnProperty(num)) {\n      freq[num] = 0\n    }\n\n    freq[num] += 1\n  }\n\n  for (let i = nums.length - 1; i >= 0; i--) {\n    const num = nums[i]\n\n    if (freq[num] <= n) {\n      continue\n    }\n\n    nums.splice(i, 1)\n    freq[num] -= 1\n  }\n\n  return nums\n}\n"
  },
  {
    "path": "codewars/double_cola.js",
    "content": "function whoIsNext(names, r) {\n  let total = names.length\n\n  while (r > total) {\n    r -= total\n    total *= 2\n  }\n\n  return names[parseInt(names.length * (r - 1) / total)]\n}\n"
  },
  {
    "path": "codewars/iq_test.js",
    "content": "function iqTest(nums) {\n  nums = nums.split(' ').map(c => +c & 1)\n\n  for (let i = 2; i < nums.length; i++) {\n    if (nums[0] ^ nums[i] && nums[1] ^ nums[i]) {\n      return i + 1\n    } else if (nums[i] ^ nums[0] && nums[1] ^ nums[0]) {\n      return 1\n    } else if (nums[0] ^ nums[1] && nums[i] ^ nums[1]) {\n      return 2\n    }\n  }\n\n  return -1\n}\n"
  },
  {
    "path": "codewars/is_a_number_prime.js",
    "content": "function isPrime(num) {\n  if (!num || num <= 1) return false\n\n  const factors = [2, 3, 5, 7, 9, 11, 13, 17, 19].filter(base => {\n    if (num <= base) return false\n    if (num % base === 0) return true\n    return false\n  })\n\n  return factors.length === 0\n}\n"
  },
  {
    "path": "codewars/multiply.js",
    "content": "function multiply(a, b) {\n  return a * b\n}\n"
  },
  {
    "path": "codewars/rectangle_into_squares.js",
    "content": "function sqInRect(lng, wdth) {\n  if (!lng || !wdth || lng === wdth) return null\n\n  const ans = []\n\n  while (lng != 1 || wdth != 1) {\n    if (lng > wdth) {\n      ans.push(wdth)\n      lng -= wdth\n    } else if (lng < wdth) {\n      ans.push(lng)\n      wdth -= lng\n    } else {\n      ans.push(lng)\n      break\n    }\n  }\n\n  if (lng == 1 && wdth == 1) {\n    ans.push(1)\n  }\n\n  return ans\n}\n"
  },
  {
    "path": "codewars/reverse_words.js",
    "content": "function reverseWords(s) {\n  return s.split(' ').map(word => {\n    return word.split('').reverse().join('')\n  }).join(' ')\n}\n"
  },
  {
    "path": "codewars/simple_encryption_1_alternating_split.js",
    "content": "function encrypt(text, n) {\n  if (!text || !n || n < 0) return text\n\n  const TEXT_SIZE = text.length\n\n  while (n--) {\n    const _text = []\n\n    for (let i = 1; i < TEXT_SIZE; i += 2) {\n      _text.push(text[i])\n    }\n\n    for (let i = 0; i < TEXT_SIZE; i += 2) {\n      _text.push(text[i])\n    }\n\n    text = _text.join('')\n  }\n\n  return text\n}\n\nfunction decrypt(text, n) {\n  if (!text || !n || n < 0) return text\n\n  const TEXT_SIZE = text.length\n  const HALF_TEXT_SIZE = parseInt(text.length / 2)\n\n  while (n--) {\n    const _text = []\n\n    for (let i = 0; i < HALF_TEXT_SIZE + 1; i++) {\n      if (HALF_TEXT_SIZE + i < TEXT_SIZE) {\n        _text.push(text[HALF_TEXT_SIZE + i])\n      }\n\n      if (i < HALF_TEXT_SIZE) {\n        _text.push(text[i])\n      }\n    }\n\n    text = _text.join('')\n  }\n\n  return text\n}\n"
  },
  {
    "path": "codewars/sudoku_solution_validator.js",
    "content": "function validSolution(board) {\n  if ( !Array.isArray(board)\n    || !Array.isArray(board[0])\n    || board.length !== board[0].length) {\n    return false\n  }\n\n  const n = board.length\n  const g = Math.sqrt(n)  // group counts\n\n  const cnts = new Array(n).fill(0)\n  let cnt = 0\n  let i, j, x, y\n\n  for (x = 0; x < n; x++) {\n    for (y = 0; y < n; y++) {\n      if (board[x][y] <= 0 || board[x][y] > n) return false\n      if (cnts[board[x][y] - 1] !== cnt) return false\n      cnts[board[x][y] - 1] += 1\n    }\n    cnt += 1\n\n    for (y = 0; y < n; y++) {\n      if (board[y][x] <= 0 || board[y][x] > n) return false\n      if (cnts[board[y][x] - 1] !== cnt) return false\n      cnts[board[y][x] - 1] += 1\n    }\n    cnt += 1\n  }\n\n  let x_from, x_to, y_from, y_to\n\n  for (i = 0; i < g; i++) {\n    for (j = 0; j < g; j++) {\n      x_from = i * g\n      x_to = i * g + g\n      y_from = j * g\n      y_to = j * g + g\n      for (x = x_from; x < x_to; x++) {\n        for (y = y_from; y < y_to; y++) {\n          if (cnts[board[x][y] - 1] !== cnt) return false\n          cnts[board[x][y] - 1] += 1\n        }\n      }\n      cnt += 1\n    }\n  }\n\n  return true\n}\n"
  },
  {
    "path": "codewars/take_a_ten_minute_walk.js",
    "content": "function isValidWalk(walk) {\n  if (walk.length != 10) {\n    return false\n  }\n\n  let dx = 0\n  let dy = 0\n\n  walk.forEach(c => {\n    switch (c) {\n      case 'n':\n        dy++\n        break\n      case 's':\n        dy--\n        break\n      case 'e':\n        dx++\n        break\n      case 'w':\n        dx--\n        break\n      default:\n        return false\n    }\n  })\n\n  return dx === 0 && dy === 0\n}\n"
  },
  {
    "path": "codewars/tribonacci_sequence.js",
    "content": "function tribonacci(signature, n) {\n  if (!n) return []\n\n  const ans = signature.slice()\n\n  for (let i = 3; i < n; i++) {\n    ans.push(ans[i - 3] + ans[i - 2] + ans[i - 1])\n  }\n\n  return ans.slice(0, n)\n}\n"
  },
  {
    "path": "codewars/unique_in_order.js",
    "content": "function uniqueInOrder(iterable) {\n  if (!iterable) {\n    return []\n  }\n\n  const ans = [iterable[0]]\n\n  for (let i = 1; i < iterable.length; i++) {\n    if (iterable[i] != ans[ans.length - 1]) {\n      ans.push(iterable[i])\n    }\n  }\n\n  return ans\n}\n"
  },
  {
    "path": "codewars/who_likes_it.js",
    "content": "function likes(names) {\n  if (!Array.isArray(names) || names.length === 0) {\n    return 'no one likes this'\n  }\n\n  switch (names.length) {\n    case 1:\n      return `${names[0]} likes this`\n    case 2:\n      return `${names[0]} and ${names[1]} like this`\n    case 3:\n      return `${names[0]}, ${names[1]} and ${names[2]} like this`\n    default:\n      return `${names[0]}, ${names[1]} and ${names.length - 2} others like this`\n  }\n}\n"
  },
  {
    "path": "leetcode/101_symmetric_tree.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    def isSymmetric(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        if not root:\n            return True\n\n        return self.divide_conquer(root.left, root.right)\n\n    def divide_conquer(self, left, right):\n        if not left and not right:\n            return True\n        if not left or not right:\n            return False\n        if left.val != right.val:\n            return False\n        if not self.divide_conquer(left.left, right.right):\n            return False\n        if not self.divide_conquer(left.right, right.left):\n            return False\n        return True\n"
  },
  {
    "path": "leetcode/105_construct_binary_tree_from_preorder_and_inorder_traversal.py",
    "content": "# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\n\nclass Solution(object):\n    def buildTree(self, P, I):\n        \"\"\"\n        :type P: List[int]\n        :type I: List[int]\n        :rtype: TreeNode\n        \"\"\"\n        if not P or not I:\n            return\n\n        i = I.index(P.pop(0))\n        node = TreeNode(I[i])\n        node.left = self.buildTree(P, I[:i])\n        node.right = self.buildTree(P, I[i + 1:])\n        return node\n"
  },
  {
    "path": "leetcode/108_convert_sorted_array_to_binary_search_tree.py",
    "content": "# Definition for a binary tree node.\n# class TreeNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\n\nclass Solution:\n    def sortedArrayToBST(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: TreeNode\n        \"\"\"\n        if not nums:\n            return\n\n        i = len(nums) // 2\n        node = TreeNode(nums[i])\n        node.left = self.sortedArrayToBST(nums[:i])\n        node.right = self.sortedArrayToBST(nums[i + 1:])\n\n        return node\n"
  },
  {
    "path": "leetcode/112_path_sum.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    def hasPathSum(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        if not root:\n            return False\n\n        if not root.left and not root.right:\n            return root.val == target\n\n        if root.left and self.hasPathSum(root.left, target - root.val):\n            return True\n\n        if root.right and self.hasPathSum(root.right, target - root.val):\n            return True\n\n        return False\n"
  },
  {
    "path": "leetcode/113_path_sum_ii.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    def pathSum(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not root:\n            return ans\n\n        self.dfs(root, target, ans, [])\n\n        return ans\n\n    def dfs(self, node, remaining, ans, path):\n        if not node:\n            return\n\n        path.append(node.val)\n\n        if not node.left and not node.right and remaining == node.val:\n            ans.append(path[:])\n        else:\n            self.dfs(node.left, remaining - node.val, ans, path)\n            self.dfs(node.right, remaining - node.val, ans, path)\n\n        path.pop()\n"
  },
  {
    "path": "leetcode/116_populating_next_right_pointers_in_each_node.py",
    "content": "\"\"\"\nDefinition for binary tree with next pointer.\nclass TreeLinkNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Recursion\n    \"\"\"\n    def connect(self, root):\n        \"\"\"\n        :type root: TreeLinkNode\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        if root.left:\n            root.left.next = root.right\n\n        if root.right and root.next:\n            root.right.next = root.next.left\n\n        # leave to None if root.right: root.right.next = None\n\n        self.connect(root.left)\n        self.connect(root.right)\n\n\nclass Solution:\n    \"\"\"\n    Iteration\n    \"\"\"\n    def connect(self, root):\n        \"\"\"\n        :type root: TreeLinkNode\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        head = root\n        nxt = None\n\n        # this loop only for find left\n        while head:\n            nxt = head\n            head = nxt.left\n\n            # this loop find for every next, do level move\n            while nxt:\n                if nxt.left:\n                    nxt.left.next = nxt.right\n\n                if nxt.right and nxt.next:\n                    nxt.right.next = nxt.next.left\n\n                nxt = nxt.next\n"
  },
  {
    "path": "leetcode/117_populating_next_right_pointers_in_each_node_ii.py",
    "content": "\"\"\"\nDefinition for binary tree with next pointer.\nclass TreeLinkNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Recursion\n    1. recursion from right to left\n    2. first scan the nxt by level\n    \"\"\"\n    def connect(self, root):\n        \"\"\"\n        :type root: TreeLinkNode\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        # scan the nxt by level\n        head = root.next\n        nxt = None\n\n        while head and not nxt:\n            if head.left:\n                nxt = head.left\n            elif head.right:\n                nxt = head.right\n            else:\n                head = head.next\n\n        if root.right:\n            root.right.next = nxt\n            nxt = root.right\n\n        if root.left:\n            root.left.next = nxt\n\n        self.connect(root.right)\n        self.connect(root.left)\n\n\nclass Solution:\n    \"\"\"\n    Iteration\n    \"\"\"\n    def connect(self, root):\n        \"\"\"\n        :type root: TreeLinkNode\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        dummy = TreeLinkNode(0)\n        dummy.next = root\n        nxt = tail = None\n\n        while dummy.next:\n            tail = dummy\n            nxt = dummy.next\n            dummy.next = None\n\n            while nxt:\n                if nxt.left:\n                    tail.next = nxt.left\n                    tail = tail.next\n\n                if nxt.right:\n                    tail.next = nxt.right\n                    tail = tail.next\n\n                nxt = nxt.next\n\n\nclass Solution:\n    \"\"\"\n    Level Traversal\n    \"\"\"\n    def connect(self, root):\n        \"\"\"\n        :type root: TreeLinkNode\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        queue, _queue = [root], []\n\n        while queue:\n            n = len(queue)\n\n            for i in range(n):\n                if i < n - 1:\n                    queue[i].next = queue[i + 1]\n\n                if queue[i].left:\n                    _queue.append(queue[i].left)\n\n                if queue[i].right:\n                    _queue.append(queue[i].right)\n\n            queue, _queue = _queue, []\n"
  },
  {
    "path": "leetcode/118_pascal_s_triangle.py",
    "content": "class Solution:\n    def generate(self, num_rows):\n        \"\"\"\n        :type num_rows: int\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n        if not num_rows:\n            return ans\n\n        ans.append([1])\n\n        for i in range(1, num_rows):\n            path = [ans[i - 1][0]]\n\n            for j in range(1, len(ans[i - 1])):\n                path.append(ans[i - 1][j] + ans[i - 1][j - 1])\n\n            path.append(ans[i - 1][-1])\n            ans.append(path)\n\n        return ans\n\n\nclass Solution:\n    def generate(self, num_rows):\n        \"\"\"\n        :type num_rows: int\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n        if not num_rows:\n            return ans\n\n        ans.append([1])\n\n        for i in range(1, num_rows):\n            ans.append([\n                (ans[i - 1] + [0])[j] + ([0] + ans[i - 1])[j]\n                for j in range(len(ans[i - 1]) + 1)\n            ])\n\n        return ans\n"
  },
  {
    "path": "leetcode/11_container_with_most_water.py",
    "content": "class Solution:\n    def maxArea(self, H):\n        \"\"\"\n        :type H: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not H:\n            return ans\n\n        left, right = 0, len(H) - 1\n        while left < right:\n            area = min(H[left], H[right]) * (right - left)\n            if area > ans:\n                ans = area\n\n            if H[left] < H[right]:\n                left += 1\n            else:\n                right -= 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/124_binary_tree_maximum_path_sum.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    def maxPathSum(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        ans, _ = self.divide_conquer(root)\n        return ans\n\n    def divide_conquer(self, node):\n        if not node:\n            return float('-inf'), 0\n\n        max_left, left = self.divide_conquer(node.left)\n        max_right, right = self.divide_conquer(node.right)\n\n        # 0 means discard the negative path\n        res = max(max_left, max_right, node.val + left + right)\n        path = max(node.val + left, node.val + right, 0)\n\n        return res, path\n\n\nclass Solution:\n    def maxPathSum(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        self.ans = float('-inf')\n        self.divide_conquer(root)\n        return self.ans\n\n    def divide_conquer(self, node):\n        if not node:\n            return 0\n\n        left = max(0, self.divide_conquer(node.left))\n        right = max(0, self.divide_conquer(node.right))\n\n        if node.val + left + right > self.ans:\n            self.ans = node.val + left + right\n\n        return node.val + max(left, right)\n"
  },
  {
    "path": "leetcode/134_gas_station.py",
    "content": "class Solution:\n    \"\"\"\n    Main Concept:\n\n    if the tank is enough, go to next, otherwise back to previous to get gas\n    \"\"\"\n    def canCompleteCircuit(self, gas, cost):\n        \"\"\"\n        :type gas: List[int]\n        :type cost: List[int]\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = -1\n\n        if not gas or not cost or len(gas) != len(cost):\n            return NOT_FOUND\n\n        end, start = -1, len(gas) - 1  # since its a circle, end start from `-1` means `n - 1`\n        tank = gas[start] - cost[start]\n\n        while start > end:\n            if tank >= 0:\n                end += 1\n                tank += gas[end] - cost[end]\n            else:\n                start -= 1\n                tank += gas[start] - cost[start]\n\n        return start if tank >= 0 else NOT_FOUND\n\n\nclass Solution:\n    \"\"\"\n    TLE: Simulate the process\n    \"\"\"\n    def canCompleteCircuit(self, gas, cost):\n        \"\"\"\n        :type gas: List[int]\n        :type cost: List[int]\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = -1\n\n        if not gas or not cost or len(gas) != len(cost):\n            return NOT_FOUND\n\n        n = len(gas)\n        RANGE = list(range(n))\n\n        for start in range(n):\n            tank = 0\n            is_failed = False\n\n            for mid in RANGE[start:n] + RANGE[:start]:\n                tank += gas[mid]\n                if tank < cost[mid]:\n                    is_failed = True\n                    break\n                tank -= cost[mid]\n\n            if not is_failed:\n                return start\n\n        return NOT_FOUND\n"
  },
  {
    "path": "leetcode/136_single_number.py",
    "content": "class Solution:\n    def singleNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        for num in nums:\n            ans ^= num\n        return ans\n"
  },
  {
    "path": "leetcode/149_max_points_on_a_line.py",
    "content": "# Definition for a point.\n# class Point:\n#     def __init__(self, a=0, b=0):\n#         self.x = a\n#         self.y = b\n\n\nclass Solution:\n    def maxPoints(self, P):\n        \"\"\"\n        :type P: List[Point]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not P:\n            return ans\n\n        n = len(P)\n        if n <= 2:\n            return n\n\n        for i in range(n):\n            S = {}\n            points = dups = 0\n            for j in range(i + 1, n):\n                dx = P[i].x - P[j].x\n                dy = P[i].y - P[j].y\n                if dx == 0 and dy == 0:\n                    dups += 1\n                    continue\n\n                gcd = self.get_gcd(dx, dy)\n                if gcd:\n                    dx //= gcd\n                    dy //= gcd\n\n                key = (dx, dy)\n                S[key] = S.get(key, 0) + 1\n\n                if S[key] > points:\n                    points = S[key]\n\n            if points + dups + 1 > ans:\n                ans = points + dups + 1\n\n        return ans\n\n    def get_gcd(self, a, b):\n        if b == 0:\n            return a\n        return self.get_gcd(b, a % b)\n"
  },
  {
    "path": "leetcode/14_longest_common_prefix.py",
    "content": "class Solution:\n    def longestCommonPrefix(self, strs):\n        \"\"\"\n        :type strs: List[str]\n        :rtype: str\n        \"\"\"\n        if not strs or not strs[0]:\n            return ''\n\n        t = strs[0]\n        for i in range(len(t)):\n            for s in strs:\n                if i >= len(s) or s[i] != t[i]:\n                    return t[:i]\n\n        return t\n"
  },
  {
    "path": "leetcode/150_evaluate_reverse_polish_notation.py",
    "content": "class Solution:\n    def evalRPN(self, E):\n        \"\"\"\n        :type E: List[str]\n        :rtype: int\n        \"\"\"\n        if not E:\n            return 0\n\n        stack = []\n        operation = {\n            '+': lambda a, b: a + b,\n            '-': lambda a, b: a - b,\n            '*': lambda a, b: a * b,\n            '/': lambda a, b: a / b,\n        }\n\n        for char in E:\n            if char not in operation:\n                stack.append(int(char))\n                continue\n\n            b = stack.pop()\n            a = stack.pop()\n\n            stack.append(int(operation[char](a, b)))\n\n        return stack[0]\n"
  },
  {
    "path": "leetcode/157_read_n_characters_given_read4.py",
    "content": "\"\"\"\nThe read4 API is already defined for you.\n@param buf, a list of characters\n@return an integer\n\ndef read4(buf):\n    pass\n\"\"\"\n\n\nclass Solution:\n    def read(self, buf, n):\n        \"\"\"\n        :type buf: List[str], Destination buffer\n        :type n: int, Maximum number of characters to read\n        :rtype: int, The number of characters read\n        \"\"\"\n        if not buf or n <= 0:\n            return 0\n\n        i = 0\n        k = 4\n        tmp = [0] * k\n\n        while i < n and k == 4:\n            k = read4(tmp)\n            j = 0\n\n            while i < n and j < k:\n                buf[j] = tmp[j]\n                i += 1\n                j += 1\n\n        return i\n\n\nif __name__ == '__main__':\n    data = 'abcdferrdsjfklsdjfdsr'\n    n = len(data)\n    i = 0\n    k = 4\n\n    def read4(buf):\n        global i\n        j = 0\n\n        while i < n and j < k:\n            buf[j] = data[i]\n            i += 1\n            j += 1\n\n        return j\n\n    s = Solution()\n    res = s.read([0] * 4, 4)\n    print(res)\n"
  },
  {
    "path": "leetcode/160_intersection_of_two_linked_lists.py",
    "content": "# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\n\nclass Solution(object):\n    def getIntersectionNode(self, A, B):\n        \"\"\"\n        :type A, B: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not A or not B:\n            return\n\n        X, Y = A, B\n\n        while X and Y:\n            X = X.next\n            Y = Y.next\n\n        while X:\n            X = X.next\n            A = A.next\n\n        while Y:\n            Y = Y.next\n            B = B.next\n\n        while A is not B:\n            A = A.next\n            B = B.next\n\n        return A\n"
  },
  {
    "path": "leetcode/165_compare_version_numbers.py",
    "content": "class Solution:\n    def compareVersion(self, version1, version2):\n        \"\"\"\n        :type version1: str\n        :type version2: str\n        :rtype: int\n        \"\"\"\n        if not version1 and not version2:\n            return 0\n        if not version1:\n            return -1\n        if not version2:\n            return 1\n\n        v = version1.split('.')\n        w = version2.split('.')\n        m, n = len(v), len(w)\n\n        for i in range(max(m, n)):\n            a = self.get_int(v[i]) if i < m else 0\n            b = self.get_int(w[i]) if i < n else 0\n\n            if a < b:\n                return -1\n            elif a > b:\n                return 1\n\n        return 0\n\n    def get_int(self, s):\n        if not s or not s.isdigit():\n            return 0\n\n        res = 0\n        zero = ord('0')\n\n        for c in s:\n            res = res * 10 + ord(c) - zero\n\n        return res\n"
  },
  {
    "path": "leetcode/166_fraction_to_recurring_decimal.py",
    "content": "class Solution:\n    def fractionToDecimal(self, a, b):\n        \"\"\"\n        :type a: int\n        :type b: int\n        :rtype: str\n        \"\"\"\n        if not b:\n            return ''\n        if not a:\n            return '0'\n\n        ans = []\n        if a ^ b < 0:\n            ans.append('-')\n\n        if a < 0:\n            a = -a\n        if b < 0:\n            b = -b\n\n        ans.append(str(a // b))\n\n        a %= b\n        if a == 0:\n            return ''.join(ans)\n\n        ans.append('.')\n        D = {a: len(ans)}  # the index of first occurrence of `a`\n        while a:\n            a *= 10\n            ans.append(str(a // b))\n            a %= b\n\n            if a in D:\n                ans.insert(D[a], '(')\n                ans.append(')')\n                break\n\n            D[a] = len(ans)\n\n        return ''.join(ans)\n"
  },
  {
    "path": "leetcode/169_majority_element.py",
    "content": "class Solution:\n    def majorityElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        ans = None\n        cnt = 0\n\n        for num in nums:\n            if cnt == 0:\n                ans, cnt = num, 1\n            elif ans == num:\n                cnt += 1\n            else:\n                cnt -= 1\n\n        return ans\n\n\nclass Solution:\n    def majorityElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        nums.sort()\n\n        return nums[len(nums) // 2]\n\n\nclass Solution:\n    def majorityElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = 0\n\n        if not nums:\n            return NOT_FOUND\n\n        freq = {}\n\n        for a in nums:\n            freq[a] = freq.get(a, 0) + 1\n\n        for a, cnt in freq.items():\n            if cnt > len(nums) // 2:\n                return a\n\n        return NOT_FOUND\n"
  },
  {
    "path": "leetcode/171_excel_sheet_column_number.py",
    "content": "class Solution:\n    def titleToNumber(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return 0\n\n        s = s.upper()\n\n        ans = 0\n        BASE = ord('A') - 1\n\n        for char in s:\n            ans = ans * 26 + ord(char) - BASE\n\n        return ans\n"
  },
  {
    "path": "leetcode/172_factorial_trailing_zeroes.py",
    "content": "class Solution:\n    def trailingZeroes(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not n:\n            return ans\n\n        i = 5\n        while n // i > 0:\n            ans += n // i\n            i *= 5\n\n        return ans\n"
  },
  {
    "path": "leetcode/174_dungeon_game.py",
    "content": "class Solution:\n    def calculateMinimumHP(self, G):\n        \"\"\"\n        :type G: List[List[int]]\n        :rtype: int\n        \"\"\"\n        INFINITY = float('inf')\n        m, n = len(G), len(G[0])\n        dp = [[INFINITY] * (n + 1) for _ in range(m + 1)]\n        dp[m][n - 1] = 1\n        dp[m - 1][n] = 1\n\n        for i in range(m - 1, -1, -1):\n            for j in range(n - 1, -1, -1):\n                dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - G[i][j]\n                if dp[i][j] <= 0:\n                    dp[i][j] = 1\n\n        return dp[0][0]\n"
  },
  {
    "path": "leetcode/179_largest_number.py",
    "content": "\"\"\"\nREF: https://leetcode.com/articles/largest-number/\n\"\"\"\n\n\nclass LgSort(str):\n    def __lt__(a, b):\n        return a + b > b + a\n\n\nclass Solution:\n    def largestNumber(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: str\n        \"\"\"\n        A = ''.join(sorted(map(str, A), key=LgSort))\n        return '0' if A[0] == '0' else A\n"
  },
  {
    "path": "leetcode/17_letter_combinations_of_a_phone_number.py",
    "content": "class Solution:\n    def letterCombinations(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        if not s:\n            return []\n\n        L = {\n            '2': 'abc', '3': 'def',  '4': 'ghi', '5': 'jkl',\n            '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz',\n        }\n\n        queue, _queue = [], []\n        for d in s:\n            if d not in L:\n                return []\n            if not queue:\n                queue.extend(list(L[d]))\n                continue\n\n            for c in L[d]:\n                for _c in queue:\n                    _queue.append(_c + c)\n            queue, _queue = _queue, []\n\n        queue.sort()\n        return queue\n"
  },
  {
    "path": "leetcode/190_reverse_bits.py",
    "content": "# Reverse bit every 4 bits\nclass Solution:\n    # @param n, an integer\n    # @return an integer\n    def reverseBits(self, n):\n        if not n:\n            return 0\n\n        # the reversed bins for i = 0 -> 15\n        rev = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]\n        ans = 0\n        msk = 15  # 15 (10) == 1111 (2)\n\n        for i in range(8):\n            ans <<= 4\n            curr = n & msk\n            ans |= rev[curr]\n            n >>= 4\n\n        return ans\n\n\n# Reverse bit every 1 bits\nclass Solution:\n    # @param n, an integer\n    # @return an integer\n    def reverseBits(self, n):\n        ans = 0\n\n        if not n:\n            return ans\n\n        for i in range(32):\n            ans <<= 1\n            ans |= n & 1\n            n >>= 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/191_number_of_1_bits.py",
    "content": "class Solution:\n    def hammingWeight(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not n:\n            return ans\n\n        while n != 0:\n            n = n & (n - 1)\n            ans += 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/19_remove_nth_node_from_end_of_list.py",
    "content": "\"\"\"\nDefinition for singly-linked list.\nclass ListNode:\n    def __init__(self, x):\n        self.val = x\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    def removeNthFromEnd(self, head, n):\n        \"\"\"\n        :type head: ListNode\n        :type n: int\n        :rtype: ListNode\n        \"\"\"\n        if not head or not n:\n            return head\n\n        dummy = slow = ListNode(0)\n        dummy.next = fast = head\n\n        while fast and n:\n            n -= 1\n            fast = fast.next\n\n        while slow and fast:\n            slow = slow.next\n            fast = fast.next\n\n        if slow and slow.next:\n            slow.next = slow.next.next\n\n        return dummy.next\n"
  },
  {
    "path": "leetcode/202_happy_number.py",
    "content": "class Solution:\n    def isHappy(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        slow = self.square_sum(n)\n        fast = self.square_sum(slow)\n\n        while slow != fast:\n            slow = self.square_sum(slow)\n            fast = self.square_sum(\n                self.square_sum(fast)\n            )\n\n        return True if slow == 1 else False\n\n    def square_sum(self, a):\n        res = b = 0\n\n        while a != 0:\n            b = a % 10\n            res += b * b\n            a //= 10\n\n        return res\n"
  },
  {
    "path": "leetcode/204_count_primes.py",
    "content": "\"\"\"\nREF: https://discuss.leetcode.com/topic/14036/fast-python-solution\n\nCount the number of prime numbers LESS THAN a non-negative number, n.\n\"\"\"\n\n\nclass Solution:\n    def countPrimes(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        # note that 2 is prime\n        # but there is no prime less than 2\n        # so return 0 if n == 2\n        if not n or n < 3:\n            return 0\n\n        is_prime = [True] * n\n        is_prime[0] = is_prime[1] = False\n\n        for i in range(2, int(n ** 0.5) + 1):\n            if not is_prime[i]:\n                continue\n            for j in range(i * i, n, i):\n                is_prime[j] = False\n\n        return sum(is_prime)\n"
  },
  {
    "path": "leetcode/208_implement_trie_prefix_tree.py",
    "content": "class TrieNode:\n    def __init__(self, val=None):\n        self.end_at = val\n        self.children = {}\n\n\nclass Trie:\n    def __init__(self):\n        self.trie = TrieNode()\n\n    def insert(self, word):\n        \"\"\"\n        Inserts a word into the trie.\n        :type word: str\n        :rtype: void\n        \"\"\"\n        if not word:\n            return\n\n        node = self.trie\n        for char in word:\n            if char not in node.children:\n                node.children[char] = TrieNode()\n            node = node.children[char]\n        node.end_at = word\n\n    def search(self, word):\n        \"\"\"\n        Returns if the word is in the trie.\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        if not word:\n            return False\n\n        node = self.trie\n        for char in word:\n            if char not in node.children:\n                return False\n            node = node.children[char]\n        return node.end_at == word\n\n    def startsWith(self, prefix):\n        \"\"\"\n        Returns if there is any word in the trie that starts with the given prefix.\n        :type prefix: str\n        :rtype: bool\n        \"\"\"\n        if not prefix:\n            return False\n\n        node = self.trie\n        for char in prefix:\n            if char not in node.children:\n                return False\n            node = node.children[char]\n        return True\n\n\n# Your Trie object will be instantiated and called as such:\n# obj = Trie()\n# obj.insert(word)\n# param_2 = obj.search(word)\n# param_3 = obj.startsWith(prefix)\n"
  },
  {
    "path": "leetcode/20_valid_parentheses.py",
    "content": "class Solution:\n    def isValid(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        stack = []\n        pairs = {')': '(', ']': '[', '}': '{'}\n\n        for c in s:\n            if c in '([{':\n                stack.append(c)\n            elif c not in ')]}':\n                return False\n            elif not stack or pairs[c] != stack.pop():\n                return False\n\n        return not stack\n"
  },
  {
    "path": "leetcode/215_kth_largest_element_in_an_array.py",
    "content": "from heapq import heappop, heappush\n\n\nclass Solution:\n    def findKthLargest(self, A, k):\n        \"\"\"\n        :type A: List[int]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        heap = []\n\n        for a in A:\n            heappush(heap, a)\n            if len(heap) > k:\n                heappop(heap)\n\n        return heappop(heap)\n"
  },
  {
    "path": "leetcode/217_contains_duplicate.py",
    "content": "class Solution:\n    def containsDuplicate(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: bool\n        \"\"\"\n        if not A:\n            return False\n\n        S = set()\n\n        for a in A:\n            if a in S:\n                return True\n            S.add(a)\n\n        return False\n"
  },
  {
    "path": "leetcode/218_the_skyline_problem.py",
    "content": "\"\"\"\nREF: https://briangordon.github.io/2014/08/the-skyline-problem.html\n\"\"\"\nimport heapq\n\n\nclass HashHeapq:\n    def __init__(self):\n        self.heap = []\n        self.deleted = {}\n\n    def push(self, val):\n        heapq.heappush(self.heap, val)\n\n    def pop(self):\n        if self.is_empty():\n            return -1\n\n        return heapq.heappop(self.heap)\n\n    def remove(self, val):\n        if self.is_empty():\n            return\n\n        if val not in self.deleted:\n            self.deleted[val] = 0\n\n        self.deleted[val] += 1\n\n    def top(self):\n        if self.is_empty():\n            return -1\n\n        return self.heap[0]\n\n    def is_empty(self):\n        while self.heap and self.deleted.get(self.heap[0]):\n            val = heapq.heappop(self.heap)\n            self.deleted[val] -= 1\n\n        return not self.heap\n\n\nclass Solution:\n    def getSkyline(self, buildings):\n        \"\"\"\n        :type buildings: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n        if not buildings:\n            return ans\n\n        time = []\n\n        for x, _x, height in buildings:\n            time.append((x, height, True))\n            time.append((_x, height, False))\n\n        time.sort()\n        heap = HashHeapq()\n\n        for x, height, is_start in time:\n            if is_start:\n                heap.push(-height)\n            else:\n                heap.remove(-height)\n\n            max_h = -heap.top() if not heap.is_empty() else 0\n\n            if ans and ans[-1][0] == x:\n                ans.pop()\n            if ans and ans[-1][1] == max_h:\n                continue\n            ans.append([x, max_h])\n\n        return ans\n"
  },
  {
    "path": "leetcode/224_basic_calculator.py",
    "content": "class Solution:\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return 0\n\n        self.OP = {\n            '+': lambda a, b: a + b,\n            '-': lambda a, b: a - b,\n        }\n\n        s = self.to_rpn(s)\n\n        if not s:\n            return 0\n\n        return self.eval_rpn(s)\n\n    def to_rpn(self, s):\n        stack, res = [], []\n\n        for i in range(len(s)):\n            char = s[i]\n\n            if i > 0 and s[i - 1].isdigit() and char.isdigit():\n                res[-1] += char\n            elif char.isdigit():\n                res.append(char)\n            elif char in self.OP:\n                while stack and stack[-1] in self.OP:\n                    res.append(stack.pop())\n                stack.append(char)\n            elif char == '(':\n                stack.append(char)\n            elif char == ')':\n                while stack and stack[-1] != '(':\n                    res.append(stack.pop())\n                stack.pop()\n\n        while stack:\n            res.append(stack.pop())\n\n        return res\n\n    def eval_rpn(self, s):\n        stack = []\n\n        for char in s:\n            if char.isdigit():\n                stack.append(int(char))\n            elif char in self.OP:\n                b = stack.pop()\n                a = stack.pop()\n                stack.append(self.OP[char](a, b))\n\n        return stack[0]\n\n\nclass Solution:\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return 0\n\n        s = self.to_rpn(s)\n\n        if not s:\n            return 0\n\n        return self.eval_rpn(s)\n\n    def to_rpn(self, s):\n        stack, res = [], []\n\n        for i in range(len(s)):\n            char = s[i]\n\n            if i > 0 and s[i - 1].isdigit() and char.isdigit():\n                res[-1] += char\n            elif char.isdigit():\n                res.append(char)\n            elif char in '+-':\n                while stack and stack[-1] in '+-':\n                    res.append(stack.pop())\n                stack.append(char)\n            elif char == '(':\n                stack.append(char)\n            elif char == ')':\n                while stack and stack[-1] != '(':\n                    res.append(stack.pop())\n                stack.pop()\n\n        while stack:\n            res.append(stack.pop())\n\n        return res\n\n    def eval_rpn(self, s):\n        stack = []\n\n        for char in s:\n            if char.isdigit():\n                stack.append(int(char))\n            elif char in '+-':\n                b = stack.pop()\n                a = stack.pop()\n\n                if char == '+':\n                    stack.append(a + b)\n                elif char == '-':\n                    stack.append(a - b)\n\n        return stack[0]\n"
  },
  {
    "path": "leetcode/227_basic_calculator_ii.py",
    "content": "class Solution:\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return 0\n\n        s = self.to_rpn(s, {\n            '+': 1,\n            '-': 1,\n            '*': 2,\n            '/': 2,\n        })\n\n        if not s:\n            return 0\n\n        return self.eval_rpn(s, {\n            '+': lambda a, b: a + b,\n            '-': lambda a, b: a - b,\n            '*': lambda a, b: a * b,\n            '/': lambda a, b: a // b,\n        })\n\n    def to_rpn(self, s, P):\n        stack, res = [], []\n\n        for i in range(len(s)):\n            char = s[i]\n\n            if i > 0 and s[i - 1].isdigit() and char.isdigit():\n                res[-1] += char\n            elif char.isdigit():\n                res.append(char)\n            elif char in P:\n                while stack and stack[-1] in P and P[char] <= P[stack[-1]]:\n                    res.append(stack.pop())\n                stack.append(char)\n            elif char == '(':\n                stack.append(char)\n            elif char == ')':\n                while stack and stack[-1] != '(':\n                    res.append(stack.pop())\n                stack.pop()\n\n        while stack:\n            res.append(stack.pop())\n\n        return res\n\n    def eval_rpn(self, s, OP):\n        stack = []\n\n        for char in s:\n            if char.isdigit():\n                stack.append(int(char))\n            elif char in OP:\n                b = stack.pop()\n                a = stack.pop()\n                stack.append(OP[char](a, b))\n\n        return stack[0]\n\n\nclass Solution:\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return 0\n\n        s = self.to_rpn(s)\n\n        if not s:\n            return 0\n\n        return self.eval_rpn(s)\n\n    def to_rpn(self, s):\n        stack, res = [], []\n\n        for i in range(len(s)):\n            char = s[i]\n\n            if i > 0 and s[i - 1].isdigit() and char.isdigit():\n                res[-1] += char\n            elif char.isdigit():\n                res.append(char)\n            elif char in '+-*/':\n                while stack and stack[-1] in '+-*/':\n                    if char in '*/' and stack[-1] in '+-':\n                        break\n                    res.append(stack.pop())\n                stack.append(char)\n            elif char == '(':\n                stack.append(char)\n            elif char == ')':\n                while stack and stack[-1] != '(':\n                    res.append(stack.pop())\n                stack.pop()\n\n        while stack:\n            res.append(stack.pop())\n\n        return res\n\n    def eval_rpn(self, s):\n        stack = []\n\n        for char in s:\n            if char.isdigit():\n                stack.append(int(char))\n            elif char in '+-*/':\n                b = stack.pop()\n                a = stack.pop()\n\n                if char == '+':\n                    stack.append(a + b)\n                elif char == '-':\n                    stack.append(a - b)\n                elif char == '*':\n                    stack.append(a * b)\n                elif char == '/':\n                    stack.append(a // b)\n\n        return stack[0]\n"
  },
  {
    "path": "leetcode/229_majority_element_ii.py",
    "content": "class Solution:\n    def majorityElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not nums:\n            return []\n\n        a1 = a2 = None\n        c1 = c2 = 0\n\n        for num in nums:\n            if a1 == num:\n                c1 += 1\n            elif a2 == num:\n                c2 += 1\n            elif c1 == 0:\n                a1, c1 = num, 1\n            elif c2 == 0:\n                a2, c2 = num, 1\n            else:\n                c1 -= 1\n                c2 -= 1\n\n        c1 = c2 = 0\n\n        for num in nums:\n            if num == a1:\n                c1 += 1\n            elif num == a2:\n                c2 += 1\n\n        for a, c in ((a1, c1), (a2, c2)):\n            if c > len(nums) // 3:\n                ans.append(a)\n\n        return ans\n"
  },
  {
    "path": "leetcode/22_generate_parentheses.py",
    "content": "class Solution:\n    def generateParenthesis(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: list[str]\n        \"\"\"\n        ans = []\n        if not n:\n            return ans\n\n        self.dfs(n, 1, 0, ans, ['('])\n        return ans\n\n    def dfs(self, n, lcnt, rcnt, ans, path):\n        if len(path) == 2 * n:\n            ans.append(''.join(path))\n            return\n\n        if rcnt < lcnt:\n            path.append(')')\n            self.dfs(n, lcnt, rcnt + 1, ans, path)\n            path.pop()\n\n        if lcnt < n:\n            path.append('(')\n            self.dfs(n, lcnt + 1, rcnt, ans, path)\n            path.pop()\n"
  },
  {
    "path": "leetcode/230_kth_smallest_element_in_a_bst.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    def kthSmallest(self, root, k):\n        \"\"\"\n        :type root: TreeNode\n        :type k: int\n        :rtype: int\n        \"\"\"\n        if not root:\n            return\n\n        stack = []\n        node = root\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n\n            k -= 1\n            if k == 0:\n                return node.val\n\n            node = node.right\n"
  },
  {
    "path": "leetcode/234_palindrome_linked_list.py",
    "content": "# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\n\nclass Solution:\n    def isPalindrome(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        rev = None\n        slow = fast = head\n\n        while fast and fast.next:\n            fast = fast.next.next\n            rev, rev.next, slow = slow, rev, slow.next\n\n        if fast:\n            slow = slow.next\n\n        while slow and slow.val == rev.val:\n            slow = slow.next\n            rev = rev.next\n\n        return not rev\n\n\nclass Solution:\n    def isPalindrome(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        rev = nxt = None\n        slow = fast = head\n\n        while fast and fast.next:\n            fast = fast.next.next\n\n            nxt = slow.next\n            slow.next = rev\n            rev = slow\n            slow = nxt\n\n        if fast:\n            slow = slow.next\n\n        while slow and slow.val == rev.val:\n            slow = slow.next\n            rev = rev.next\n\n        return not rev\n"
  },
  {
    "path": "leetcode/235_lowest_common_ancestor_of_a_binary_search_tree.py",
    "content": "# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\n\nclass Solution(object):\n    def lowestCommonAncestor(self, root, p, q):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        while root:\n            if root.val > p.val and root.val > q.val:\n                root = root.left\n            elif root.val < p.val and root.val < q.val:\n                root = root.right\n            else:\n                return root\n"
  },
  {
    "path": "leetcode/236_lowest_common_ancestor_of_a_binary_tree.py",
    "content": "# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\n\nclass Solution(object):\n    def lowestCommonAncestor(self, root, p, q):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or root is p or root is q:\n            return root\n\n        left = self.lowestCommonAncestor(root.left, p, q)\n        right = self.lowestCommonAncestor(root.right, p, q)\n\n        if left and right:\n            return root\n        if left:\n            return left\n        if right:\n            return right\n"
  },
  {
    "path": "leetcode/237_delete_node_in_a_linked_list.py",
    "content": "# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\n\nclass Solution(object):\n    def deleteNode(self, node):\n        \"\"\"\n        :type node: ListNode\n        :rtype: void Do not return anything, modify node in-place instead.\n        \"\"\"\n        if not node or not node.next:\n            return\n\n        node.val = node.next.val\n        node.next = node.next.next\n"
  },
  {
    "path": "leetcode/242_valid_anagram.py",
    "content": "class Solution:\n    def isAnagram(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        if s == t:\n            return True\n        if not s or not t or len(s) != len(t):\n            return False\n\n        freq = {}\n\n        for c in s:\n            freq[c] = freq.get(c, 0) + 1\n\n        for c in t:\n            if c not in freq:\n                return False\n\n            freq[c] -= 1\n\n        return all(v == 0 for v in freq.values())\n"
  },
  {
    "path": "leetcode/269_alien_dictionary.py",
    "content": "class Solution:\n    def alienOrder(self, words):\n        \"\"\"\n        :type words: list[str]\n        :rtype: str\n        \"\"\"\n        if not words:\n            return ''\n\n        ans = []\n        gotcha = set()\n        max_size = max(len(word) for word in words)\n\n        for j in range(max_size):\n            for word in words:\n                if j >= len(word):\n                    continue\n\n                if word[j] in gotcha:\n                    continue\n\n                ans.append(word[j])\n                gotcha.add(word[j])\n\n        return ''.join(ans)\n\n\nclass Solution:\n    \"\"\"\n    REF: https://discuss.leetcode.com/topic/28308/java-ac-solution-using-bfs/2\n    \"\"\"\n    def alienOrder(self, words):\n        if not words:\n            return ''\n\n        ans = []\n        edges = {}\n        indeg = {}\n\n        for w in words:\n            for c in w:\n                indeg[c] = 0\n\n        for i in range(len(words) - 1):\n            cur = words[i]\n            nxt = words[i + 1]\n            for j in range(min(len(cur), len(nxt))):\n                if cur[j] == nxt[j]:\n                    continue\n                if cur[j] not in edges:\n                    edges[cur[j]] = set()\n                if nxt[j] not in edges[cur[j]]:\n                    edges[cur[j]].add(nxt[j])\n                    indeg[nxt[j]] = indeg.get(nxt[j], 0) + 1\n                break\n\n        queue = [c for c, deg in indeg.items() if deg == 0]\n        for c in queue:\n            ans.append(c)\n            if c not in edges:\n                continue\n            for _c in edges[c]:\n                indeg[_c] -= 1\n                if indeg[_c] == 0:\n                    queue.append(_c)\n\n        return ''.join(ans) if len(ans) == len(indeg) else ''\n"
  },
  {
    "path": "leetcode/277_find_the_celebrity.py",
    "content": "\"\"\"\nREF: https://discuss.leetcode.com/topic/25720/java-python-o-n-calls-o-1-space-easy-to-understand-solution\n\"\"\"\n\n\nclass Solution:\n    def findCelebrity(self, n):\n        if not n:\n            return -1\n\n        x = 0\n\n        for i in range(n):\n            if knows(x, i):\n                x = i\n\n        for i in range(x):\n            if knows(x, i):\n                return -1\n\n        for i in range(n):\n            if not knows(i, x):\n                return -1\n\n        return x\n"
  },
  {
    "path": "leetcode/280_wiggle_sort.py",
    "content": "class Solution:\n    def wiggleSort(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: void, Do not return anything, modify A in-place instead.\n        \"\"\"\n        if not nums:\n            return\n\n        for i in range(1, len(nums)):\n            if i & 1 == 1 and nums[i] >= nums[i - 1]:\n                continue\n            if i & 1 == 0 and nums[i] <= nums[i - 1]:\n                continue\n\n            nums[i], nums[i - 1] = nums[i - 1], nums[i]\n"
  },
  {
    "path": "leetcode/282_expression_add_operators.py",
    "content": "\"\"\"\nMain Concept:\n\nin product case, needs to remove product in last recursion, and adds the product in current.\n\"\"\"\n\n\nclass Solution:\n    def addOperators(self, s, target):\n        \"\"\"\n        :type s: str\n        :type target: int\n        :rtype: List[str]\n        \"\"\"\n        ans = []\n\n        if not s:\n            return ans\n\n        self.dfs(s, 0, target, 0, 0, ans, [])\n        return ans\n\n    def dfs(self, s, start, target, val, multi, ans, path):\n        if start == len(s) and target == val:\n            ans.append(''.join(path))\n            return\n        if start >= len(s):\n            return\n\n        for i in range(start, len(s)):\n            if i > start and s[start] == '0':\n                # only allow i == start and its `0`\n                break\n\n            sa = s[start:i + 1]\n            a = int(sa)\n\n            if start == 0:\n                self.dfs(s, i + 1, target, a, a, ans, [sa])\n                continue\n\n            self.dfs(s, i + 1, target, val + a, a, ans, path + ['+', sa])\n            self.dfs(s, i + 1, target, val - a, -a, ans, path + ['-', sa])\n            self.dfs(s, i + 1, target, val - multi + multi * a, multi * a, ans, path + ['*', sa])\n"
  },
  {
    "path": "leetcode/285_inorder_successor_in_bst.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\n>>> class TreeNode:\n...     def __init__(self, x):\n...         self.val = x\n...         self.left = None\n...         self.right = None\n...         self.parent = None\n\n>>> trees = []\n>>> tree_infos = [\n...     ((\n...         (1, None, None, 2),\n...         (2, 1, None, None),\n...     ), '1,2'),\n...     ((\n...         (20, None, 8, 22),\n...         (8, 20, 4, 12),\n...         (22, 20, None, None),\n...         (4, 8, None, None),\n...         (12, 8, 10, 14),\n...         (10, 12, None, None),\n...         (14, 12, None, None),\n...     ), '4,8,10,12,14,20,22'),\n...     ((\n...         (10, None, 5, 100),\n...         (5, 10, None, None),\n...         (100, 10, 80, 120),\n...         (80, 100, None, None),\n...         (120, 100, None, None),\n...     ), '5,10,80,100,120'),\n...     ((\n...         (1, None, None, 2),\n...         (2, 1, None, 3),\n...         (3, 2, None, 4),\n...         (4, 3, None, 5),\n...         (5, 4, None, 6),\n...         (6, 5, None, 7),\n...         (7, 6, None, None),\n...     ), '1,2,3,4,5,6,7'),\n... ]\n\n>>> for info, _ in tree_infos:\n...     nodes = {node[0]: TreeNode(node[0]) for node in info}\n...\n...     for val, parent, left, right in info:\n...         if parent:\n...             nodes[val].parent = nodes[parent]\n...         if left:\n...             nodes[val].left = nodes[left]\n...         if right:\n...             nodes[val].right = nodes[right]\n...\n...     trees.append(nodes[info[0][0]])\n\n>>> gotcha = []\n>>> for _in, _out in (\n...     ((trees[0], trees[0]), trees[0].right),\n...     ((trees[1], trees[1].left.right.right), trees[1]),\n... ):\n...     for s in (Solution(), Solution2(), Solution3(), Solution4()):\n...         res = s.inorderSuccessor(*_in)\n...         if res is not _out: print(_in[0].val, res.val)\n...         gotcha.append(res is _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    time: O(log n) or O(h), `n` is the number of nodes and `h` is the tree height\n\n    1. if `target` has right child, then successor lies at the most-left child in right child of `target`\n    2. otherwise, just traverse down from root, and record `ans` when every time go left\n    \"\"\"\n    def inorderSuccessor(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or not target:\n            return\n\n        ans = None\n\n        if target.right:\n            ans = target.right\n            while ans and ans.left:\n                ans = ans.left\n            return ans\n\n        while root and target.val != root.val:\n            if target.val < root.val:\n                ans = root\n                root = root.left\n            else:\n                root = root.right\n\n        return ans\n\n\nclass Solution2:\n    \"\"\"\n    time: O(n), `n` is the number of nodes\n\n    just do inorder traverse\n    \"\"\"\n    def inorderSuccessor(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or not target:\n            return\n\n        stack = []\n        node = root\n        got_target = False\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n\n            if got_target:\n                return node\n            if node.val == target.val:\n                got_target = True\n\n            node = node.right\n\n\nclass Solution3:\n    \"\"\"\n    * every node has `parent` pointer\n    time: O(log n) or O(h), `n` is the number of nodes and `h` is the tree height\n\n    1. if `target` has right child, then successor lies at the most-left child in right child of `target`\n    2. otherwise, just traverse top to root\n    \"\"\"\n    def inorderSuccessor(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or not target:\n            return\n\n        ans = None\n\n        if target.right:\n            ans = target.right\n            while ans and ans.left:\n                ans = ans.left\n            return ans\n\n        ans = target.parent\n        while ans and target is ans.right:\n            target = ans\n            ans = ans.parent\n\n        return ans\n\n\nclass Solution4:\n    \"\"\"\n    * every node has `parent` pointer\n    time: O(log n) or O(h), `n` is the number of nodes and `h` is the tree height\n\n    1. if `target` has right child, then successor lies at the most-left child in right child of `target`\n    2. otherwise, just traverse top to root\n    \"\"\"\n    def inorderSuccessor(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or not target:\n            return\n\n        if target.right:\n            ans = target.right\n            while ans and ans.left:\n                ans = ans.left\n            return ans\n\n        ans = target.parent\n        while ans and ans.val < target.val:\n            ans = ans.parent\n\n        return ans\n"
  },
  {
    "path": "leetcode/288_unique_word_abbreviation.py",
    "content": "\"\"\"\nYour ValidWordAbbr object will be instantiated and called as such:\nvwa = ValidWordAbbr(dictionary)\nvwa.isUnique(\"word\")\nvwa.isUnique(\"anotherWord\")\n\nTesting:\n>>> s = ValidWordAbbr(['deer', 'door', 'cake', 'card'])\n>>> all((\n...     s.isUnique('dear') is False,\n...     s.isUnique('cart') is True,\n...     s.isUnique('cane') is False,\n...     s.isUnique('make') is True,\n... ))\nTrue\n\"\"\"\n\n\nclass ValidWordAbbr:\n    def __init__(self, dictionary):\n        \"\"\"\n        initialize your data structure here.\n        :type dictionary: List[str]\n        \"\"\"\n        self.abbrs = {}\n\n        for word in dictionary:\n            abbr = self.abbreviation(word)\n            self.abbrs[abbr] = word\n\n    def isUnique(self, word):\n        \"\"\"\n        check if a word is unique.\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        abbr = self.abbreviation(word)\n        return abbr not in self.abbrs\n\n    def abbreviation(self, word):\n        if len(word) < 3:\n            return word\n\n        cnt = len(word) - 2\n        return '{}{}{}'.format(\n            word[0],\n            str(cnt),\n            word[-1]\n        )\n"
  },
  {
    "path": "leetcode/289_game_of_life.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/game-of-life/discuss/73223\n\nlives < 2       => 1 -> 0\nlives == 2 or 3 => 1 -> 1\nlives > 3       => 1 -> 0\nlives == 3      => 0 -> 1\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Use bits to save the status in next round\n    \"\"\"\n    def gameOfLife(self, board):\n        \"\"\"\n        :type board: List[List[int]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        if not board or not board[0]:\n            return\n\n        m, n = len(board), len(board[0])\n\n        for x in range(m):\n            for y in range(n):\n                lives = self.get_live_neibs(board, x, y)\n\n                if board[x][y] == 1 and lives in (2, 3):\n                    board[x][y] = 3\n                elif board[x][y] == 0 and lives == 3:\n                    board[x][y] = 2\n\n        for x in range(m):\n            for y in range(n):\n                board[x][y] >>= 1\n\n    def get_live_neibs(self, board, x, y):\n        cnt = 0\n        m, n = len(board), len(board[0])\n\n        for dx in (-1, 0, 1):\n            for dy in (-1, 0, 1):\n                if dx == 0 and dy == 0:\n                    continue\n\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n\n                cnt += board[_x][_y] & 1\n\n        return cnt\n\n\nclass Solution:\n    \"\"\"\n    Not in-place solution\n    \"\"\"\n    def gameOfLife(self, board):\n        \"\"\"\n        :type board: List[List[int]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        if not board or not board[0]:\n            return\n\n        m, n = len(board), len(board[0])\n        ans = [[0] * n for _ in range(m)]\n\n        for x in range(m):\n            for y in range(n):\n                lives = self.get_live_neibs(board, x, y)\n                ans[x][y] = board[x][y]\n\n                if board[x][y] == 1 and lives < 2:\n                    ans[x][y] = 0\n                elif board[x][y] == 1 and lives in (2, 3):\n                    ans[x][y] = 1\n                elif board[x][y] == 1 and lives > 3:\n                    ans[x][y] = 0\n                elif board[x][y] == 0 and lives == 3:\n                    ans[x][y] = 1\n\n        # return ans\n\n        # hacking for in-place\n        for x in range(m):\n            board[x][:] = ans[x][:]\n\n    def get_live_neibs(self, board, x, y):\n        cnt = 0\n        m, n = len(board), len(board[0])\n\n        for dx in (-1, 0, 1):\n            for dy in (-1, 0, 1):\n                if dx == 0 and dy == 0:\n                    continue\n\n                _x = x + dx\n                _y = y + dy\n\n                if not (\n                    0 <= _x < m and\n                    0 <= _y < n and\n                    board[_x][_y] == 1\n                ):\n                    continue\n\n                cnt += 1\n\n        return cnt\n"
  },
  {
    "path": "leetcode/295_find_median_from_data_stream.py",
    "content": "\"\"\"\nYour MedianFinder object will be instantiated and called as such:\nobj = MedianFinder()\nobj.addNum(num)\nparam_2 = obj.findMedian()\n\"\"\"\nimport heapq\n\n\nclass MedianFinder:\n    def __init__(self):\n        self.minheap = []\n        self.maxheap = []\n\n    def addNum(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: void\n        \"\"\"\n        if self.minheap and num < self.minheap[0]:\n            heapq.heappush(self.maxheap, -num)\n        else:\n            heapq.heappush(self.minheap, num)\n\n    def findMedian(self):\n        \"\"\"\n        :rtype: float\n        \"\"\"\n        if not self.minheap:\n            return 0.0\n\n        # to handle odd case, it make sure `minheap` has one more child than `maxheap`\n        while len(self.minheap) > len(self.maxheap) + 1:\n            heapq.heappush(self.maxheap, - heapq.heappop(self.minheap))\n\n        # to handle even case, it make sure `minheap` and `maxheap` are same size\n        while len(self.maxheap) > len(self.minheap):\n            heapq.heappush(self.minheap, - heapq.heappop(self.maxheap))\n\n        if len(self.minheap) > len(self.maxheap):\n            return self.minheap[0] * 1.0\n\n        # since the child in maxheap is negative\n        return (self.minheap[0] - self.maxheap[0]) / 2.0\n"
  },
  {
    "path": "leetcode/299_bulls_and_cows.py",
    "content": "class Solution:\n    def getHint(self, secret, guess):\n        \"\"\"\n        :type secret: str\n        :type guess: str\n        :rtype: str\n        \"\"\"\n        if not secret or not guess or len(secret) != len(guess):\n            return ''\n\n        TMPL = '{}A{}B'\n        bulls = 0\n        cows = 0\n        cnts = [0] * 10\n\n        for i in range(len(secret)):\n            s = ord(secret[i]) - ord('0')\n            g = ord(guess[i]) - ord('0')\n\n            if s == g:\n                bulls += 1\n                continue\n\n            cnts[s] += 1\n            cnts[g] -= 1\n\n            if cnts[s] <= 0:\n                cows += 1\n            if cnts[g] >= 0:\n                cows += 1\n\n        return TMPL.format(bulls, cows)\n\n\nclass Solution:\n    def getHint(self, secret, guess):\n        \"\"\"\n        :type secret: str\n        :type guess: str\n        :rtype: str\n        \"\"\"\n        if not secret or not guess or len(secret) != len(guess):\n            return ''\n\n        TMPL = '{}A{}B'\n        bulls = 0\n        cows = 0\n        cnt_s = [0] * 10\n        cnt_g = [0] * 10\n\n        for i in range(len(secret)):\n            if secret[i] == guess[i]:\n                bulls += 1\n            else:\n                cnt_s[int(secret[i])] += 1\n                cnt_g[int(guess[i])] += 1\n\n        for i in range(10):\n            cows += min(cnt_s[i], cnt_g[i])\n\n        return TMPL.format(bulls, cows)\n"
  },
  {
    "path": "leetcode/303_range_sum_query_immutable.py",
    "content": "\"\"\"\nYour NumArray object will be instantiated and called as such:\nobj = NumArray(nums)\nparam_1 = obj.sumRange(i,j)\n\"\"\"\n\n\nclass NumArray:\n    def __init__(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        \"\"\"\n        if not nums:\n            return\n\n        n = len(nums)\n        self.prefix_sum = [0] * (n + 1)\n\n        for i in range(1, n + 1):\n            self.prefix_sum[i] = self.prefix_sum[i - 1] + nums[i - 1]\n\n    def sumRange(self, i, j):\n        \"\"\"\n        :type i: int\n        :type j: int\n        :rtype: int\n        \"\"\"\n        if (\n            not self.prefix_sum or\n            i < 0 or\n            j + 1 >= len(self.prefix_sum)\n        ):\n            return 0\n        return self.prefix_sum[j + 1] - self.prefix_sum[i]\n"
  },
  {
    "path": "leetcode/304_range_sum_query_2d_immutable.py",
    "content": "\"\"\"\nYour NumMatrix object will be instantiated and called as such:\nobj = NumMatrix(matrix)\nparam_1 = obj.sumRegion(x1, y1, x2, y2)\n\"\"\"\n\n\nclass NumMatrix:\n    def __init__(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return\n\n        m, n = len(matrix), len(matrix[0])\n        self.prefix_sum = [[0] * (n + 1) for _ in range(m + 1)]\n\n        for x in range(1, m + 1):\n            for y in range(1, n + 1):\n                self.prefix_sum[x][y] = sum((\n                    self.prefix_sum[x - 1][y],\n                    self.prefix_sum[x][y - 1],\n                    - self.prefix_sum[x - 1][y - 1],\n                    matrix[x - 1][y - 1],\n                ))\n\n    def sumRegion(self, x1, y1, x2, y2):\n        \"\"\"\n        :type x1: int\n        :type y1: int\n        :type x2: int\n        :type y2: int\n        :rtype: int\n        \"\"\"\n        if not all((\n            self.prefix_sum,\n            self.prefix_sum[0],\n            0 <= x1 < len(self.prefix_sum),\n            0 <= x2 + 1 < len(self.prefix_sum),\n            0 <= y1 < len(self.prefix_sum[0]),\n            0 <= y2 + 1 < len(self.prefix_sum[0]),\n        )):\n            return 0\n\n        return sum((\n            self.prefix_sum[x2 + 1][y2 + 1],\n            - self.prefix_sum[x2 + 1][y1],\n            - self.prefix_sum[x1][y2 + 1],\n            self.prefix_sum[x1][y1],\n        ))\n"
  },
  {
    "path": "leetcode/307_range_sum_query_mutable.py",
    "content": "\"\"\"\nREF: https://cs.stackexchange.com/questions/10538/bit-what-is-the-intuition-behind-a-binary-indexed-tree-and-how-was-it-thought-a\nREF: http://www.cnblogs.com/grandyang/p/4985506.html\n\nYour NumArray object will be instantiated and called as such:\nobj = NumArray(nums)\nobj.update(i,val)\nparam_2 = obj.sumRange(i,j)\n\"\"\"\n\n\nclass NumArray:\n    def __init__(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        \"\"\"\n        if not nums:\n            return\n\n        n = len(nums)\n        self.bits = [0] * (n + 1)  # bits\n        self.incr = [0] * (n + 1)  # increments\n\n        for i in range(n):\n            self.update(i, nums[i])\n\n    def update(self, i, val):\n        \"\"\"\n        :type i: int\n        :type val: int\n        :rtype: void\n\n        It must increase `i` here, since this api is public,\n        so look from outside, the `i` is just the index of `nums`\n        \"\"\"\n        j = i + 1\n        delta = val - self.incr[j]\n        self.incr[j] = val\n\n        while j < len(self.incr):\n            self.bits[j] += delta\n            j += (j & -j)\n\n    def sumRange(self, i, j):\n        \"\"\"\n        :type i: int\n        :type j: int\n        :rtype: int\n        \"\"\"\n        return self.sum(j + 1) - self.sum(i)\n\n    def sum(self, i):\n        res = 0\n        j = i\n\n        while j > 0:\n            res += self.bits[j]\n            j -= (j & -j)\n\n        return res\n"
  },
  {
    "path": "leetcode/308_range_sum_query_2d_mutable.py",
    "content": "\"\"\"\nYour NumMatrix object will be instantiated and called as such:\nobj = NumMatrix(matrix)\nobj.update(x,y,val)\nparam_1 = obj.sumRegion(x1,y1,x2,y2)\n\"\"\"\n\n\nclass NumMatrix:\n    def __init__(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return\n\n        m, n = len(matrix), len(matrix[0])\n        self.bits = [[0] * (n + 1) for _ in range(m + 1)]  # bits\n        self.incr = [[0] * (n + 1) for _ in range(m + 1)]  # increments\n\n        for x in range(m):\n            for y in range(n):\n                self.update(x, y, matrix[x][y])\n\n    def update(self, x, y, val):\n        \"\"\"\n        :type x: int\n        :type y: int\n        :type val: int\n        :rtype: void\n        \"\"\"\n        i = x + 1\n        j = y + 1\n\n        delta = val - self.incr[i][j]\n        self.incr[i][j] = val\n\n        m, n = len(self.incr), len(self.incr[0])\n\n        while i < m:\n            j = y + 1\n            while j < n:\n                self.bits[i][j] += delta\n                j += (j & -j)\n            i += (i & -i)\n\n    def sumRegion(self, x1, y1, x2, y2):\n        \"\"\"\n        :type x1: int\n        :type y1: int\n        :type x2: int\n        :type y2: int\n        :rtype: int\n        \"\"\"\n        return sum((\n            self.sum(x2 + 1, y2 + 1),\n            - self.sum(x1, y2 + 1),\n            - self.sum(x2 + 1, y1),\n            self.sum(x1, y1),\n        ))\n\n    def sum(self, x, y):\n        res = 0\n        i = x\n        j = y\n\n        while i > 0:\n            j = y\n            while j > 0:\n                res += self.bits[i][j]\n                j -= (j & -j)\n            i -= (i & -i)\n\n        return res\n"
  },
  {
    "path": "leetcode/30_substring_with_concatenation_of_all_words.py",
    "content": "class Solution:\n    def findSubstring(self, s, S):\n        \"\"\"\n        :type s: str\n        :type S: List[str]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n        if not s or not S or len(s) < len(S) * len(S[0]):\n            return ans\n\n        n, m, k = len(s), len(S), len(S[0])\n        F = {}\n        for c in S:\n            F[c] = F.get(c, 0) + 1\n\n        for start in range(k):\n            _F = {}\n            cnt = 0\n            left = start\n\n            for right in range(start, n - k + 1, k):\n                sr = s[right:right + k]\n                if sr not in F:\n                    _F = {}\n                    cnt = 0\n                    left = right + k\n                    continue\n\n                _F[sr] = _F.get(sr, 0) + 1\n                if _F[sr] <= F[sr]:\n                    cnt += 1\n                while _F[sr] > F[sr]:\n                    sl = s[left:left + k]\n                    if _F[sl] == F[sl]:\n                        cnt -= 1\n                    _F[sl] -= 1\n                    left += k\n\n                if cnt == m:\n                    ans.append(left)\n                    sl = s[left:left + k]\n                    cnt -= 1\n                    _F[sl] -= 1\n                    left += k\n\n        return ans\n"
  },
  {
    "path": "leetcode/315_count_of_smaller_numbers_after_self.py",
    "content": "class Solution:\n    \"\"\"\n    REF: https://leetcode.com/problems/count-of-smaller-numbers-after-self/discuss/76657/\n    \"\"\"\n    def countSmaller(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[int]\n        \"\"\"\n        if not nums:\n            return []\n\n        n = len(nums)\n        ans = [0] * n\n\n        cands = sorted(set(nums))\n        v2i = {cands[i]: i for i in range(len(cands))}\n        self.bits = [0] * (len(v2i) + 1)\n\n        for i in range(n - 1, -1, -1):\n            j = v2i[nums[i]]\n            ans[i] = self.sum(j)\n            self.update(j)\n\n        return ans\n\n    def update(self, i):\n        i += 1\n\n        while i < len(self.bits):\n            self.bits[i] += 1\n            i += (i & -i)\n\n    def sum(self, i):\n        res = 0\n\n        while i > 0:\n            res += self.bits[i]\n            i -= (i & -i)\n\n        return res\n\n\nclass Solution:\n    \"\"\"\n    Brute Force: TLE\n    \"\"\"\n    def countSmaller(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not nums:\n            return ans\n\n        n = len(nums)\n\n        for i in range(n):\n            ans.append(0)\n\n            for j in range(i, n):\n                if nums[j] < nums[i]:\n                    ans[-1] += 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/323_number_of_connected_components_in_an_undirected_graph.py",
    "content": "\"\"\"\nTesting:\n>>> gotcha = []\n>>> for s in (Solution(), Solution2()):\n...     for _in, _out in (\n...         ((5, [[0, 1], [1, 2], [3, 4]]), 2),\n...         ((5, [[0, 1], [1, 2], [2, 3], [3, 4]]), 1),\n...     ):\n...         res = s.countComponents(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Union Find\n    \"\"\"\n    def countComponents(self, n, edges):\n        \"\"\"\n        :type n: int\n        :type edges: list[int]\n        :rtype: int\n        \"\"\"\n        if not n or not edges:\n            return 0\n\n        nodes = [i for i in range(n)]\n\n        ans = n\n\n        for a, b in edges:\n            if self.union(nodes, a, b):\n                ans -= 1\n\n        return ans\n\n    def union(self, nodes, a, b):\n        _a = self.find(nodes, a)\n        _b = self.find(nodes, b)\n\n        if _a == _b:\n            return False\n\n        nodes[_b] = _a\n        return True\n\n    def find(self, nodes, a):\n        if a not in nodes:\n            nodes[a] = a\n            return a\n        if nodes[a] == a:\n            return a\n\n        nodes[a] = self.find(nodes[a])\n        return nodes[a]\n\n\nclass Solution2:\n    \"\"\"\n    DFS\n    \"\"\"\n    def countComponents(self, n, edges):\n        \"\"\"\n        :type n: int\n        :type edges: list[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not n or not edges:\n            return ans\n\n        adj = {}\n\n        for i in range(n):\n            adj[i] = set()\n\n        for a, b in edges:\n            adj[a].add(b)\n            adj[b].add(a)\n\n        visited = set()\n\n        for i in range(n):\n            if i in visited:\n                continue\n\n            ans += 1\n            self.dfs(i, adj, visited)\n\n        return ans\n\n    def dfs(self, a, adj, visited):\n        if a not in adj:\n            return\n\n        visited.add(a)\n\n        for b in adj[a]:\n            if b in visited:\n                continue\n\n            self.dfs(b, adj, visited)\n"
  },
  {
    "path": "leetcode/324_wiggle_sort_ii.py",
    "content": "\"\"\"\nFollow Up: https://discuss.leetcode.com/topic/32929/o-n-o-1-after-median-virtual-indexing\n\"\"\"\n\n\nclass Solution:\n    def wiggleSort(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: void Do not return anything, modify A in-place instead.\n        \"\"\"\n        if not A:\n            return\n\n        n = len(A)\n        S = sorted(A)\n\n        for i in range(1, n, 2):\n            A[i] = S.pop()\n\n        for i in range(0, n, 2):\n            A[i] = S.pop()\n"
  },
  {
    "path": "leetcode/326_power_of_three.py",
    "content": "class Solution:\n    def isPowerOfThree(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        if not n:\n            return False\n\n        for i in (81, 27, 9, 3):\n            while n % i == 0:\n                n //= i\n\n        return n == 1\n"
  },
  {
    "path": "leetcode/329_longest_increasing_path_in_a_matrix.py",
    "content": "class Solution:\n    def longestIncreasingPath(self, G):\n        \"\"\"\n        :type G: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not G or not G[0]:\n            return 0\n\n        self.V = (\n            (-1,  0),\n            ( 1,  0),\n            ( 0, -1),\n            ( 0,  1),\n        )\n        ans = 1\n        m, n = len(G), len(G[0])\n        memo = [[0] * n for _ in range(m)]\n\n        for x in range(m):\n            for y in range(n):\n                size = self.dfs(G, x, y, memo)\n                if size > ans:\n                    ans = size\n\n        return ans\n\n    def dfs(self, G, x, y, memo):\n        if memo[x][y] > 0:\n            return memo[x][y]\n\n        res = 1\n\n        for dx, dy in self.V:\n            _x = x + dx\n            _y = y + dy\n            if not (0 <= _x < len(G) and 0 <= _y < len(G[0])):\n                continue\n            if G[x][y] >= G[_x][_y]:\n                continue\n            size = 1 + self.dfs(G, _x, _y, memo)\n            if size > res:\n                res = size\n\n        memo[x][y] = res\n        return res\n"
  },
  {
    "path": "leetcode/334_increasing_triplet_subsequence.py",
    "content": "class Solution:\n    def increasingTriplet(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: bool\n        \"\"\"\n        if not A:\n            return False\n\n        a = b = float('inf')\n\n        for x in A:\n            if x <= a:\n                a = x\n            elif x <= b:\n                b = x\n            else:\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/33_search_in_rotated_sorted_array.py",
    "content": "class Solution:\n    def search(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = -1\n\n        if not nums:\n            return NOT_FOUND\n\n        left, right = 0, len(nums) - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n\n            if nums[mid] == target:\n                return mid\n\n            if nums[mid] < nums[0]:\n                if nums[mid] < target <= nums[right]:\n                    left = mid\n                else:\n                    right = mid\n            else:\n                if nums[left] <= target < nums[mid]:\n                    right = mid\n                else:\n                    left = mid\n\n        for mid in (left, right):\n            if nums[mid] == target:\n                return mid\n\n        return NOT_FOUND\n"
  },
  {
    "path": "leetcode/340_longest_substring_with_at_most_k_distinct_characters.py",
    "content": "\"\"\"\n- count chars: minimum length: `while cnt == k` to reduce window size if possible\n- count chars: maximum length: `while cnt > k` to record the maximum window size\n\"\"\"\n\n\nimport collections\n\n\nclass Solution:\n    def lengthOfLongestSubstringKDistinct(self, s, k):\n        \"\"\"\n        :type s: str\n        :type k: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not s or not k or k < 0:\n            return ans\n\n        freqs = collections.defaultdict(int)\n        i = cnt = 0\n\n        for j in range(len(s)):\n            freqs[s[j]] += 1\n            if freqs[s[j]] == 1:\n                cnt += 1\n\n            while cnt > k:\n                freqs[s[i]] -= 1\n                if freqs[s[i]] == 0:\n                    cnt -= 1\n\n                i += 1\n\n            ans = max(ans, j - i + 1)\n\n        return ans\n"
  },
  {
    "path": "leetcode/344_reverse_string.py",
    "content": "class Solution:\n    def reverseString(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        return ''.join(reversed(s))\n"
  },
  {
    "path": "leetcode/347_top_k_frequent_elements.py",
    "content": "class Solution:\n    def topKFrequent(self, A, k):\n        \"\"\"\n        :type A: List[int]\n        :type k: int\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n        if not A:\n            return ans\n\n        F = {}\n        for a in A:\n            F[a] = F.get(a, 0) + 1\n\n        for a, _ in sorted(F.items(), key=lambda x: -x[1]):\n            if k == 0:\n                break\n\n            ans.append(a)\n            k -= 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/348_design_tic_tac_toe.py",
    "content": "class TicTacToe(object):\n    PLER_A = 1\n    PLER_B = 2\n\n    def __init__(self, n):\n        \"\"\"\n        Initialize your data structure here.\n        :type n: int\n        \"\"\"\n        self.R = [0] * n\n        self.C = [0] * n\n        self.DR = 0  # only one\n        self.DL = 0  # only one\n\n    def move(self, x, y, player):\n        \"\"\"\n        Player {player} makes a move at ({x}, {y}).\n        :type x: int The row of the board.\n        :type y: int The column of the board.\n        :type player: int The player, can be either 1 or 2.\n        :rtype: int The current winning condition, can be either:\n                0: No one wins.\n                1: Player 1 wins.\n                2: Player 2 wins.\n        \"\"\"\n        n = len(self.R)\n        delta = 1 if player == self.PLER_A else -1\n        self.R[x] += delta\n        self.C[y] += delta\n        self.DR += delta if x == y else 0  # x - y == 0\n        self.DL += delta if x == n - 1 - y else 0  # x + y == n - 1\n        return (abs(self.R[x]) == n or\n                abs(self.C[y]) == n or\n                abs(self.DR) == n or\n                abs(self.DL) == n)\n\n\n# Your TicTacToe object will be instantiated and called as such:\n# obj = TicTacToe(n)\n# param_1 = obj.move(x,y,player)\n"
  },
  {
    "path": "leetcode/353_design_snake_game.py",
    "content": "\"\"\"\n0. self.height is for `m`, self.width is for `n`\n1. note that, REMOVE FIRST,\n   MUST remove the snake tail **BEFORE** check it hit its body\n2. this game is over if\n    - hit wall\n    - hit it self\n    - no food\n\n3. dont pop food in every move, just track its index\n4. the score is just the len(body) - 1, except the head\n\n5. what its return if no food or food is all taken?\n6. does allow the snake just back if its body only 2?\n\n\nInitially the snake appears at position (0,0) and the food at (1,2).\nYour SnakeGame object will be instantiated and called as such:\nobj = SnakeGame(width, height, food)\nparam_1 = obj.move(direction)\n\n\n>>> snake = SnakeGame(3, 2, [[1, 2], [0, 1]])\n>>> [snake.move(d) for d in 'RDRULU']\n[0, 0, 1, 1, 2, -1]\n>>> all(snake.move(d) == -1 for d in 'LUDR')\nTrue\n\n>>> snake = SnakeGame(3, 3, [[2, 0], [0, 0]])\n>>> [snake.move(d) for d in 'DDUU']\n[0, 1, 1, 2]\n>>> all(snake.move(d) == -1 for d in 'RUDL')\nTrue\n\"\"\"\nimport collections\n\n\nclass SnakeGame:\n    def __init__(self, width, height, food):\n        \"\"\"\n        :type width: int, screen width\n        :type height: int, screen height\n        :type food: List[List[int]], A list of food positions\n\n        E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1],\n        the second is at [1,0].\n        \"\"\"\n        if not width or not height or not food:\n            # raise error\n            return\n\n        self.width = width\n        self.height = height\n        self.food = food\n        self.fi = 0\n\n        self.is_over = False\n        self.SCORE_IN_OVER = -1\n\n        pos = [(0, 0)]\n        self.snake = collections.deque(pos)\n        self.body = set(pos)\n\n        self.dn = {\n            'U': (-1,  0),\n            'D': ( 1,  0),\n            'L': ( 0, -1),\n            'R': ( 0,  1),\n        }\n\n    def move(self, direction):\n        \"\"\"Moves the snake.\n        :type direction: str, 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down\n        :rtype: int, The game's score after the move. Return -1 if game over.\n\n        Game over when snake crosses the screen boundary or bites its body.\n        \"\"\"\n        if direction not in self.dn:\n            # treat this move as invalid action\n            return len(self.snake) - 1\n\n        if self.is_over:\n            # this game is over\n            return self.SCORE_IN_OVER\n\n        \"\"\"\n        new head will hit wall?\n        \"\"\"\n        x, y = self.snake[0]\n        dx, dy = self.dn[direction]\n        hx = x + dx\n        hy = y + dy\n\n        if not (0 <= hx < self.height and 0 <= hy < self.width):\n            self.is_over = True\n            return self.SCORE_IN_OVER\n\n        \"\"\"\n        eat food or not\n        \"\"\"\n        fx, fy = self.food[self.fi]\n\n        if fx == hx and fy == hy:\n            # eat that food\n            self.fi += 1\n        else:\n            # move to empty cell and need to remove tail\n            tail = self.snake.pop()\n            self.body.discard(tail)\n\n        \"\"\"\n        new head will hit its self?\n        this detection MUST AFTER removing tail\n        \"\"\"\n        if (hx, hy) in self.body:\n            self.is_over = True\n            return self.SCORE_IN_OVER\n\n        \"\"\"\n        new head is valid, track it\n        \"\"\"\n        self.snake.appendleft((hx, hy))\n        self.body.add((hx, hy))\n\n        \"\"\"\n        There is no food anymore\n        \"\"\"\n        if self.fi >= len(self.food):\n            self.is_over = True\n\n        return len(self.snake) - 1\n"
  },
  {
    "path": "leetcode/36_valid_sudoku.py",
    "content": "class Solution:\n    def isValidSudoku(self, board):\n        \"\"\"\n        :type board: List[List[str]]\n        :rtype: bool\n        \"\"\"\n        if not board or not board[0] or len(board) != len(board[0]):\n            return False\n\n        n = len(board)\n        EMPTY = '.'\n        CANDS = '123456789'\n\n        for x in range(n):\n            used = set()\n\n            for y in range(n):\n                if board[x][y] == EMPTY:\n                    continue\n                if board[x][y] not in CANDS:\n                    return False\n                if board[x][y] in used:\n                    return False\n                used.add(board[x][y])\n\n        for y in range(n):\n            used = set()\n\n            for x in range(n):\n                if board[x][y] == EMPTY:\n                    continue\n                if board[x][y] in used:\n                    return False\n                used.add(board[x][y])\n\n        for i in range(3):\n            for j in range(3):\n                used = set()\n\n                for x in range(i * 3, i * 3 + 3):\n                    for y in range(j * 3, j * 3 + 3):\n                        if board[x][y] == EMPTY:\n                            continue\n                        if board[x][y] in used:\n                            return False\n                        used.add(board[x][y])\n\n        return True\n"
  },
  {
    "path": "leetcode/377_combination_sum_iv.py",
    "content": "\"\"\"\n- item can only pick once (even diff item with same val): num loop -> amount loop, amount from end to start, + break\n- item can pick multiple but diff order is same path: num loop -> amount loop, amount from start to end\n- item can pick multiple but diff order is diff path: amount loop -> num loop, amount from start to end\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Dynamic Programming\n    \"\"\"\n    def combinationSum4(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        dp = [0] * (target + 1)\n        dp[0] = 1\n\n        # if iterate num first, then the answer will become the number of unique set\n        # see the last Solution in this file\n        for amount in range(1, target + 1):\n            for num in nums:\n                if amount >= num:\n                    dp[amount] += dp[amount - num]\n\n        return dp[target]\n\n\nclass Solution:\n    \"\"\"\n    Memory Search /\n    Dynamic Programming /\n    DFS\n    \"\"\"\n    def combinationSum4(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        dp = [-1] * (target + 1)\n        dp[0] = 1\n        self.memo_search(nums, target, dp)\n        return dp[target]\n\n    def memo_search(self, nums, remain, dp):\n        if dp[remain] > -1:\n            return dp[remain]\n\n        res = 0\n\n        for a in nums:\n            if remain < a:\n                continue\n\n            res += self.memo_search(nums, remain - a, dp)\n\n        dp[remain] = res\n        return res\n\n\nclass Solution:\n    \"\"\"\n    DFS: TLE\n    \"\"\"\n    def combinationSum4(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        ans = []\n        nums.sort(reverse=True)\n        self.dfs(nums, target, ans, [])\n\n        return len(ans)\n\n    def dfs(self, nums, remain, ans, path):\n        if remain == 0:\n            ans.append(path[::-1])\n            return\n\n        for a in nums:\n            if remain < a:\n                continue\n\n            path.append(a)\n            self.dfs(nums, remain - a, ans, path)\n            path.pop()\n\n\n# ======\n\n\nclass Solution:\n    \"\"\"\n    Dynamic Programming: wrong answer for this question\n\n    This approach is to find the unique combination\n    \"\"\"\n    def combinationSum4(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        dp = [0] * (target + 1)\n        dp[0] = 1\n\n        for num in nums:\n            for amount in range(num, target + 1):\n                dp[amount] += dp[amount - num]\n\n        return dp[target]\n"
  },
  {
    "path": "leetcode/378_kth_smallest_element_in_a_sorted_matrix.py",
    "content": "from heapq import heappop, heappush\n\n\nclass Solution:\n    def kthSmallest(self, G, k):\n        \"\"\"\n        :type G: List[List[int]]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        if not G or not G[0]:\n            return 0\n\n        heap = []\n\n        for x in range(len(G)):\n            heappush(heap, (G[x][0], x, 0))\n\n        while heap:\n            a, x, y = heappop(heap)\n\n            k -= 1\n            if k == 0:\n                return a\n\n            if y + 1 < len(G[x]):\n                heappush(heap, (G[x][y + 1], x, y + 1))\n\n        return 0\n"
  },
  {
    "path": "leetcode/37_sudoku_solver.py",
    "content": "class Solution:\n    def solveSudoku(self, board):\n        \"\"\"\n        :type board: List[List[str]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        if not board or not board[0] or len(board) != len(board[0]):\n            return\n\n        self.dfs(board, 0, 0)\n\n    def dfs(self, board, x, y):\n        n = len(board)\n\n        if x == n:\n            return True\n\n        _x, _y = x, y + 1\n\n        if y == n - 1:\n            _x = x + 1\n            _y = 0\n\n        if board[x][y] != '.':\n            if not self.is_valid(board, x, y):\n                return False\n            return self.dfs(board, _x, _y)\n\n        for i in range(1, n + 1):\n            board[x][y] = str(i)\n            if (\n                self.is_valid(board, x, y) and\n                self.dfs(board, _x, _y)\n            ):\n                return True\n\n        board[x][y] = '.'\n        return False\n\n    def is_valid(self, board, x, y):\n        if board[x][y] not in '123456789':\n            return False\n\n        n = len(board)\n\n        for i in range(n):\n            if y != i and board[x][y] == board[x][i]:\n                return False\n            if x != i and board[x][y] == board[i][y]:\n                return False\n\n        r = x // 3 * 3\n        c = y // 3 * 3\n\n        for i in range(r, r + 3):\n            for j in range(c, c + 3):\n                if x == i and y == j:\n                    continue\n                if board[x][y] == board[i][j]:\n                    return False\n\n        return True\n"
  },
  {
    "path": "leetcode/380_insert_delete_getrandom_o1.py",
    "content": "\"\"\"\nYour RandomizedSet object will be instantiated and called as such:\nobj = RandomizedSet()\nparam = obj.insert(val)\nparam = obj.remove(val)\nparam = obj.getRandom()\n\"\"\"\nimport random\n\n\nclass RandomizedSet:\n    def __init__(self):\n        self.nums = []\n        self.val2idx = {}\n\n    def insert(self, val):\n        \"\"\"\n        Inserts a value to the set. Returns true if the set did not already contain the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        self.val2idx[val] = len(self.nums)\n        self.nums.append(val)\n\n    def remove(self, val):\n        \"\"\"\n        Removes a value from the set. Returns true if the set contained the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        if val not in self.val2idx:\n            return False\n\n        i = self.val2idx[val]\n        key = self.nums[-1]\n\n        self.val2idx[key] = i\n        self.nums[i] = self.nums[-1]\n\n        self.nums.pop()\n        del self.val2idx[val]\n        return True\n\n    def getRandom(self):\n        \"\"\"\n        Get a random element from the set.\n        :rtype: int\n        \"\"\"\n        i = random.randrange(len(self.nums))\n        return self.nums[i]\n"
  },
  {
    "path": "leetcode/381_insert_delete_getrandom_o1_duplicates_allowed.py",
    "content": "import random\n\n\nclass RandomizedCollection:\n    def __init__(self):\n        self.A = []\n        self.I = {}\n\n    def insert(self, val):\n        \"\"\"\n        Inserts a value to the collection. Returns true if the collection did not already contain the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        A, I = self.A, self.I\n        if val not in I:\n            I[val] = set()\n\n        A.append(val)\n        I[val].add(len(A) - 1)\n        return len(I[val]) == 1\n\n    def remove(self, val):\n        \"\"\"\n        Removes a value from the collection. Returns true if the collection contained the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        A, I = self.A, self.I\n        if val not in I or not I[val]:\n            return False\n\n        i = I[val].pop()\n        _val = A[-1]\n\n        I[_val].add(i)\n        I[_val].discard(len(A) - 1)\n\n        A[i] = _val\n        A.pop()\n        return True\n\n    def getRandom(self):\n        \"\"\"\n        Get a random element from the collection.\n        :rtype: int\n        \"\"\"\n        return random.choice(self.A)\n\n\n# Your RandomizedCollection object will be instantiated and called as such:\n# obj = RandomizedCollection()\n# param_1 = obj.insert(val)\n# param_2 = obj.remove(val)\n# param_3 = obj.getRandom()\n"
  },
  {
    "path": "leetcode/382_linked_list_random_node.py",
    "content": "# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nfrom random import randint\n\n\nclass Solution:\n    def __init__(self, head):\n        \"\"\"\n        @param head The linked list's head.\n        Note that the head is guaranteed to be not null, so it contains at least one node.\n        :type head: ListNode\n        \"\"\"\n        self.head = head\n\n    def getRandom(self):\n        \"\"\"\n        Returns a random node's value.\n        :rtype: int\n        \"\"\"\n        res = node = self.head\n        i = 0\n\n        while node:\n            if randint(0, i) == i:\n                res = node\n            node = node.next\n            i += 1\n\n        return res.val\n\n\n# Your Solution object will be instantiated and called as such:\n# obj = Solution(head)\n# param_1 = obj.getRandom()\n"
  },
  {
    "path": "leetcode/384_shuffle_an_array.py",
    "content": "from random import randrange\n\n\nclass Solution:\n    def __init__(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        \"\"\"\n        self.origin = nums[:]\n        self.nums = nums\n\n    def reset(self):\n        \"\"\"\n        Resets the array to its original configuration and return it.\n        :rtype: List[int]\n        \"\"\"\n        self.nums = self.origin[:]\n        return self.nums\n\n    def shuffle(self):\n        \"\"\"\n        Returns a random shuffling of the array.\n        :rtype: List[int]\n        \"\"\"\n        a = self.nums\n        n = len(a)\n\n        for i in range(n):\n            _i = randrange(i, n)\n            a[i], a[_i] = a[_i], a[i]\n\n        return a\n\n\n# Your Solution object will be instantiated and called as such:\n# obj = Solution(nums)\n# param_1 = obj.reset()\n# param_2 = obj.shuffle()\n"
  },
  {
    "path": "leetcode/386_lexicographical_numbers.py",
    "content": "class Solution:\n    def lexicalOrder(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not n:\n            return ans\n\n        stack = [1]\n\n        while stack:\n            x = stack.pop()\n            ans.append(x)\n\n            # considering the case no carry up if x + 1\n            # that is, x in [1, 8]\n            if x < n and x % 10 < 9:\n                stack.append(x + 1)\n\n            if x * 10 <= n:\n                stack.append(x * 10)\n\n        return ans\n"
  },
  {
    "path": "leetcode/387_first_unique_character_in_a_string.py",
    "content": "class Solution:\n    def firstUniqChar(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if not s:\n            return -1\n\n        freq = {}\n\n        for c in s:\n            freq[c] = freq.get(c, 0) + 1\n\n        for i in range(len(s)):\n            if freq[s[i]] == 1:\n                return i\n\n        return -1\n"
  },
  {
    "path": "leetcode/388_longest_absolute_file_path.py",
    "content": "\"\"\"\nMain Concept:\n\nif meet file, record the maximum size of the abs path `root/dir/file`\nif meet dir, save current size for `root/dir`\n\nfor files:\ntwo cases are at same depth\n1. for hidden files\n2. for extension in file\n\n\nfor dirs:\ndo NOT save the max size in each depth\nsince the children in same depth\nmay be under different parent\n\n- root\n  - p1\n    - f-loooooong-1\n  - p2\n    - f-short-2\n\nthere is error in that case if save the max size\n\"\"\"\n\n\nclass Solution:\n    def lengthLongestPath(self, path):\n        \"\"\"\n        :type path: str\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not path:\n            return ans\n\n        dep2size = {0: 0}\n\n        for line in path.split('\\n'):\n            name = line.lstrip('\\t')\n            size = len(name)\n            depth = len(line) - len(name)\n\n            if '.' in name:\n                ans = max(ans, dep2size[depth] + size)\n            else:\n                dep2size[depth + 1] = dep2size[depth] + size + 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/389_find_the_difference.py",
    "content": "class Solution:\n    def findTheDifference(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        a = ord('a')\n        ans = ord(t[-1]) - a\n\n        for i in range(len(s)):\n            ans ^= ord(s[i]) - a\n            ans ^= ord(t[i]) - a\n\n        return chr(ans + a)\n\n\nclass Solution:\n    def findTheDifference(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        if not t:\n            return ''\n\n        freq = {}\n\n        for c in s:\n            if c not in freq:\n                freq[c] = 0\n\n            freq[c] += 1\n\n        for c in t:\n            if c not in freq:\n                return c\n\n            freq[c] -= 1\n\n        for c, cnt in freq.items():\n            if cnt:\n                return c\n\n        return ''\n"
  },
  {
    "path": "leetcode/38_count_and_say.py",
    "content": "class Solution:\n    def countAndSay(self, N):\n        \"\"\"\n        :type N: int\n        :rtype: str\n        \"\"\"\n        queue = '1'\n\n        if not N:\n            return queue\n\n        _queue = []\n\n        for _ in range(N - 1):\n            cnt = 0\n            char = queue[0]\n\n            for c in queue:\n                if c == char:\n                    cnt += 1\n                    continue\n                _queue.extend((str(cnt), char))\n                cnt = 1\n                char = c\n\n            _queue.extend((str(cnt), char))\n            queue, _queue = ''.join(_queue), []\n\n        return queue\n"
  },
  {
    "path": "leetcode/390_elimination_game.py",
    "content": "class Solution:\n    def lastRemaining(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        ans = gap = 1\n        turn = 0\n\n        while n > 1:\n            turn += 1\n            n //= 2\n            gap *= 2\n            delta = gap // 2 + gap * (n - 1)\n\n            if turn & 1:\n                ans += delta\n            else:\n                ans -= delta\n\n        return ans\n"
  },
  {
    "path": "leetcode/391_perfect_rectangle.py",
    "content": "import collections\n\n\nclass Solution:\n    def isRectangleCover(self, recs):\n        \"\"\"\n        :type recs: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        if not recs:\n            return False\n\n        left = bottom = float('inf')\n        right = top = float('-inf')\n        points = collections.defaultdict(int)\n\n        for l, b, r, t in recs:\n            left = min(left, l)\n            bottom = min(bottom, b)\n            right = max(right, r)\n            top = max(top, t)\n\n            for x, y, val in (\n                (l, b, 1),\n                (r, b, 2),\n                (r, t, 4),\n                (l, t, 8),\n            ):\n                if points[x, y] & val:\n                    return False\n                points[x, y] |= val\n\n        if any(\n            # only check the mid-points\n            val not in (3, 6, 9, 12, 15)\n            for (x, y), val in points.items()\n            if left < x < right or bottom < y < top\n        ):\n            return False\n\n        return True\n"
  },
  {
    "path": "leetcode/395_longest_substring_with_at_least_k_repeating_characters.py",
    "content": "class Solution:\n    def longestSubstring(self, s, k):\n        \"\"\"\n        :type s: str\n        :type k: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not s:\n            return ans\n\n        n = len(s)\n        _F = dict.fromkeys(s, 0)\n\n        for m in range(1, len(_F) + 1):\n            F = _F.copy()\n            left = right = 0\n            kind = valid = 0\n\n            while right < n:\n                if kind <= m:\n                    F[s[right]] += 1\n                    if F[s[right]] == 1:\n                        kind += 1\n                    if F[s[right]] == k:\n                        valid += 1\n\n                    right += 1\n                else:\n                    if F[s[left]] == 1:\n                        kind -= 1\n                    if F[s[left]] == k:\n                        valid -= 1\n                    F[s[left]] -= 1\n\n                    left += 1\n\n                if kind == valid == m and right - left > ans:\n                    ans = right - left\n\n        return ans\n"
  },
  {
    "path": "leetcode/398_random_pick_index.py",
    "content": "from random import randint\n\n\nclass Solution:\n    def __init__(self, A):\n        \"\"\"\n        :type A: List[int]\n        \"\"\"\n        self.A = A\n\n    def pick(self, target):\n        \"\"\"\n        :type target: int\n        :rtype: int\n        \"\"\"\n        res = -1\n        cnt = 0\n\n        for i in range(len(self.A)):\n            if self.A[i] != target:\n                continue\n            cnt += 1\n            if randint(1, cnt) == cnt:\n                res = i\n\n        return res\n\n\n# Your Solution object will be instantiated and called as such:\n# obj = Solution(nums)\n# param_1 = obj.pick(target)\n"
  },
  {
    "path": "leetcode/399_evaluate_division.py",
    "content": "import collections\n\n\nclass Solution:\n    def calcEquation(self, equations, values, queries):\n        \"\"\"\n        :type equations: List[List[str]]\n        :type values: List[float]\n        :type queries: List[List[str]]\n        :rtype: List[float]\n        \"\"\"\n        ans = []\n\n        if not (\n            equations and\n            values and\n            queries and\n            len(equations) == len(values)\n        ):\n            return ans\n\n        nexts = collections.defaultdict(set)\n        evals = collections.defaultdict(float)\n\n        for i in range(len(equations)):\n            a, b = equations[i]\n            nexts[a].add(b)\n            nexts[b].add(a)\n            evals[a, b] = 1.0 * values[i]\n            evals[b, a] = 1.0 / values[i]\n\n        for a, b in queries:\n            res = self.dfs(a, b, 1, nexts, evals, set())\n            ans.append(float(res))\n\n        return ans\n\n    def dfs(self, a, b, val, nexts, evals, visited):\n        res = -1\n\n        if a not in nexts:\n            return res\n        if a == b:\n            # this condition must be after `a not in nexts`\n            # to prevent the node not in graph\n            return val\n\n        visited.add(a)\n\n        for c in nexts[a]:\n            if c in visited or (a, c) not in evals:\n                continue\n\n            res = self.dfs(c, b, val * evals[a, c], nexts, evals, visited)\n\n            if res != -1:\n                break\n\n        visited.discard(a)\n        return res\n"
  },
  {
    "path": "leetcode/406_queue_reconstruction_by_height.py",
    "content": "\"\"\"\nMain Concept:\n\n1. group the mans with same height and record origin index\n2. record all heights\n3. sort heights and iterate from end to start\n4. get the corresponding mans and insert to `k` index\n\ninput: [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]\n\nheights: [4, 5, 6, 7]\n\nprocess:\n\n7 [(0, 0), (1, 2)]  # input[0], input[2]\n[[7, 0]]\n[[7, 0], [7, 1]]\n\n6 [(1, 4)]\n[[7, 0], [6, 1], [7, 1]]\n\n5 [(0, 3), (2, 5)]\n[[5, 0], [7, 0], [6, 1], [7, 1]]\n[[5, 0], [7, 0], [5, 2], [6, 1], [7, 1]]\n\n4 [(4, 1)]\n[[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]]\n\"\"\"\n\n\nclass Solution:\n    def reconstructQueue(self, people):\n        \"\"\"\n        :type people: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not people:\n            return ans\n\n        people.sort(key=lambda p: (p[0], -p[1]))\n\n        for i in range(len(people) - 1, -1, -1):\n            ans.insert(people[i][1], people[i])\n\n        return ans\n\n\nclass Solution:\n    def reconstructQueue(self, people):\n        \"\"\"\n        :type people: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not people:\n            return ans\n\n        h2mans = {}\n        heights = []\n\n        for i in range(len(people)):\n            h, k = people[i]\n\n            if h in h2mans:\n                h2mans[h].append((k, i))\n            else:\n                h2mans[h] = [(k, i)]\n                heights.append(h)\n\n        heights.sort()\n\n        for height in heights[::-1]:\n            for k, i in sorted(h2mans[height]):\n                ans.insert(k, people[i])\n\n        return ans\n"
  },
  {
    "path": "leetcode/416_partition_equal_subset_sum.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/partition-equal-subset-sum/discuss/90592\n\n\n`dp[s]` means the specific sum `s` can be gotten from the sum of subset in `nums`\n\"\"\"\n\n\nclass Solution:\n    def canPartition(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return True\n\n        target = sum(nums)\n\n        if target & 1 == 1:\n            return False\n\n        target //= 2\n        dp = [False] * (target + 1)\n        dp[0] = True\n\n        for a in nums:\n            for s in range(target, a - 1, -1):\n                if dp[s]:\n                    continue\n\n                dp[s] = dp[s - a]\n\n        return dp[target]\n"
  },
  {
    "path": "leetcode/417_pacific_atlantic_water_flow.py",
    "content": "class Solution:\n    \"\"\"\n    BFS\n\n    1. for both p-side and a-side, init with queue and visit set\n    2. add the edge and do bfs\n    3. only add the cell which higher or equal the previous cell\n    4. get the intersection in both set\n    \"\"\"\n    def pacificAtlantic(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return []\n\n        m, n = len(matrix), len(matrix[0])\n        pqueue = []\n        aqueue = []\n\n        for x in range(m):\n            pqueue.append((x, 0))\n            aqueue.append((x, n - 1))\n\n        for y in range(n):\n            pqueue.append((0, y))\n            aqueue.append((m - 1, y))\n\n        pvisited = set(pqueue)\n        avisited = set(aqueue)\n\n        self.bfs(matrix, pqueue, pvisited)\n        self.bfs(matrix, aqueue, avisited)\n\n        return list(pvisited & avisited)\n\n    def bfs(self, matrix, queue, visited):\n        m, n = len(matrix), len(matrix[0])\n\n        for x, y in queue:\n            for dx, dy in (\n                (0, -1), (0, 1),\n                (-1, 0), (1, 0),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if (_x, _y) in visited:\n                    continue\n                if matrix[_x][_y] < matrix[x][y]:\n                    continue\n\n                queue.append((_x, _y))\n                visited.add((_x, _y))\n\n\nclass Solution:\n    \"\"\"\n    DFS\n    \"\"\"\n    def pacificAtlantic(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return []\n\n        m, n = len(matrix), len(matrix[0])\n        pvisited = set()\n        avisited = set()\n\n        for x in range(m):\n            self.dfs(matrix, x, 0, pvisited)\n            self.dfs(matrix, x, n - 1, avisited)\n\n        for y in range(n):\n            self.dfs(matrix, 0, y, pvisited)\n            self.dfs(matrix, m - 1, y, avisited)\n\n        return list(pvisited & avisited)\n\n    def dfs(self, matrix, x, y, visited):\n        visited.add((x, y))\n\n        for dx, dy in (\n            (0, -1), (0, 1),\n            (-1, 0), (1, 0),\n        ):\n            _x = x + dx\n            _y = y + dy\n\n            if not (\n                0 <= _x < len(matrix) and\n                0 <= _y < len(matrix[0])\n            ):\n                continue\n            if (_x, _y) in visited:\n                continue\n            if matrix[_x][_y] < matrix[x][y]:\n                continue\n\n            self.dfs(matrix, _x, _y, visited)\n"
  },
  {
    "path": "leetcode/41_first_missing_positive.py",
    "content": "\"\"\"\nREF: http://www.cnblogs.com/yuzhangcmu/p/4200096.html\n\"\"\"\n\n\nclass Solution:\n    def firstMissingPositive(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        left, right = 0, len(A) - 1\n\n        while left <= right:\n            \"\"\"\n            for `A[left]`, the index it should be at is `A[left] - 1`\n            1. if it is already at `i` => pass\n            2. if it out of range or duplicated => let `A[right]` in\n            3. if it is legal => swap to let `A[left]` go to `i`\n            \"\"\"\n            i = A[left] - 1\n            if i == left:\n                left += 1\n            elif i < 0 or i > right or A[i] == A[left]:\n                A[left], A[right] = A[right], A[left]\n                # `A[left] = A[right]` is also ok, since no need to visit `A[right]` again\n                right -= 1\n            else:\n                A[left], A[i] = A[i], A[left]\n\n        return left + 1\n"
  },
  {
    "path": "leetcode/437_path_sum_iii.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    find path count\n    \"\"\"\n    def pathSum(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        return sum((\n            self.count_valid_path(root, target),\n            self.pathSum(root.left, target),\n            self.pathSum(root.right, target),\n        ))\n\n    def count_valid_path(self, node, remaining):\n        if not node:\n            return 0\n\n        return sum((\n            int(node.val == remaining),\n            self.count_valid_path(node.left, remaining - node.val),\n            self.count_valid_path(node.right, remaining - node.val),\n        ))\n\n\nclass Solution:\n    \"\"\"\n    print path\n    \"\"\"\n    def pathSum(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: int\n        :rtype: list[list[int]]\n        \"\"\"\n        ans = []\n\n        if not root:\n            return ans\n\n        self.dfs(root, target, ans, [])\n\n        return ans\n\n    def dfs(self, node, target, ans, path):\n        if not node:\n            return\n\n        path.append(node.val)\n\n        remaining = target\n        for i in range(len(path) - 1, -1, -1):\n            remaining -= path[i]\n\n            if remaining == 0:\n                ans.append(path[i:])\n\n        self.dfs(node.left, target, ans, path)\n        self.dfs(node.right, target, ans, path)\n        path.pop()\n"
  },
  {
    "path": "leetcode/454_4sum_ii.py",
    "content": "class Solution:\n    def fourSumCount(self, A, B, C, D):\n        \"\"\"\n        :type A: List[int]\n        :type B: List[int]\n        :type C: List[int]\n        :type D: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not A or not B or not C or not D:\n            return ans\n\n        S = {}\n\n        for c in C:\n            for d in D:\n                key = - (c + d)\n                S[key] = S.get(key, 0) + 1\n\n        for a in A:\n            for b in B:\n                if a + b in S:\n                    ans += S[a + b]\n\n        return ans\n"
  },
  {
    "path": "leetcode/461_hamming_distance.py",
    "content": "class Solution:\n    def hammingDistance(self, x, y):\n        \"\"\"\n        :type x: int\n        :type y: int\n        :rtype: int\n        \"\"\"\n        n = x ^ y\n        ans = 0\n\n        if not n:\n            return ans\n\n        while n != 0:\n            n = n & (n - 1)\n            ans += 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/480_sliding_window_median.py",
    "content": "import heapq\n\n\nclass HashHeapq:\n    def __init__(self):\n        self.__heap = []\n\n    def __repr__(self):\n        return repr(self.__heap)\n\n    def __len__(self):\n        return len(self.__heap)\n\n    def __bool__(self):\n        return bool(self.__heap)\n\n    def push(self, val):\n        heapq.heappush(self.__heap, val)\n\n    def pop(self):\n        if not self.__heap:\n            return\n\n        return heapq.heappop(self.__heap)\n\n    def remove(self, val):\n        if not self.__heap:\n            return\n\n        i = 0\n        n = len(self.__heap)\n\n        while i < n and self.__heap[i] != val:\n            i += 1\n\n        if i == n:\n            return\n\n        if i == n - 1:\n            self.__heap.pop()\n        else:\n            self.__heap[i] = self.__heap[-1]\n            self.__heap.pop()\n            heapq._siftup(self.__heap, i)\n            heapq._siftdown(self.__heap, 0, i)\n\n    def top(self):\n        if not self.__heap:\n            return\n\n        return self.__heap[0]\n\n\nclass Solution:\n    def medianSlidingWindow(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: List[float]\n        \"\"\"\n        ans = []\n\n        if not nums or k <= 0 or len(nums) < k:\n            return ans\n\n        self.minheap = HashHeapq()\n        self.maxheap = HashHeapq()\n\n        for i in range(len(nums)):\n            # remove nums[i - k]\n            if i >= k:\n                if self.minheap and nums[i - k] >= self.minheap.top():\n                    self.minheap.remove(nums[i - k])\n                else:\n                    self.maxheap.remove(- nums[i - k])\n\n            # add nums[i]\n            if self.minheap and nums[i] >= self.minheap.top():\n                self.minheap.push(nums[i])\n            else:\n                self.maxheap.push(- nums[i])\n\n            # get median\n            if i >= k - 1:\n                ans.append(self.get_median())\n\n        return ans\n\n    def get_median(self):\n        if not self.minheap and not self.maxheap:\n            return 0.0\n\n        while len(self.minheap) > len(self.maxheap) + 1:\n            self.maxheap.push(- self.minheap.pop())\n\n        while len(self.maxheap) > len(self.minheap):\n            self.minheap.push(- self.maxheap.pop())\n\n        if len(self.minheap) > len(self.maxheap):\n            return self.minheap.top() * 1.0\n\n        return (self.minheap.top() - self.maxheap.top()) / 2.0\n"
  },
  {
    "path": "leetcode/486_predict_the_winner.py",
    "content": "\"\"\"\nDP:\ntime: O(n^2)\nspace: O(n)\n\"\"\"\nclass Solution:\n    def PredictTheWinner(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return False\n\n        n = len(nums)\n        dp = [0] * n\n\n        for i in range(n - 1, -1, -1):\n            for j in range(i + 1, n):\n                dp[j] = max(\n                    nums[i] - dp[j],\n                    nums[j] - dp[j - 1]\n                )\n\n        return dp[n - 1] >= 0\n\n\n\"\"\"\nDP:\ntime: O(n^2)\nspace: O(n^2)\n\"\"\"\nclass Solution:\n    def PredictTheWinner(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return False\n\n        n = len(nums)\n        dp = [[0] * n for _ in range(n)]\n\n        for i in range(n - 1, -1, -1):\n            for j in range(i + 1, n):\n                dp[i][j] = max(\n                    nums[i] - dp[i + 1][j],\n                    nums[j] - dp[i][j - 1]\n                )\n\n        return dp[0][n - 1] >= 0\n"
  },
  {
    "path": "leetcode/48_rotate_image.py",
    "content": "class Solution:\n    def rotate(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: void Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        if not matrix or not matrix[0] or len(matrix) != len(matrix[0]):\n            return\n\n        n = len(matrix)\n\n        # swap by diagonal axis\n        for i in range(n - 1):\n            for j in range(n - 1 - i):\n                x = n - 1 - j\n                y = n - 1 - i\n                matrix[i][j], matrix[x][y] = matrix[x][y], matrix[i][j]\n\n        # swap by x-mid axis\n        for i in range(n // 2):\n            for j in range(n):\n                x = n - 1 - i\n                y = j\n                matrix[i][j], matrix[x][y] = matrix[x][y], matrix[i][j]\n\n\nclass Solution:\n    def rotate(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: void Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        if not matrix or not matrix[0] or len(matrix) != len(matrix[0]):\n            return\n\n        n = len(matrix)\n        ans = [[0] * n for _ in range(n)]\n\n        for x in range(n):\n            for y in range(n):\n                ans[y][n - 1 - x] = matrix[x][y]\n\n        matrix[:] = ans[:]\n"
  },
  {
    "path": "leetcode/490_the_maze.py",
    "content": "class Solution:\n    def hasPath(self, maze, start, destination):\n        \"\"\"\n        :type maze: List[List[int]]\n        :type start: List[int]\n        :type destination: List[int]\n        :rtype: bool\n\n        >>> s = Solution()\n        >>> maze = [[0, 0, 1, 0, 0],\n        ...         [0, 0, 0, 0, 0],\n        ...         [0, 0, 0, 1, 0],\n        ...         [1, 1, 0, 1, 1],\n        ...         [0, 0, 0, 0, 0]]\n\n        >>> s.hasPath(maze, [0, 4], [4, 4])\n        True\n\n        >>> s.hasPath(maze, [0, 4], [3, 2])\n        False\n        \"\"\"\n        if not maze or not maze[0] or not start or not destination:\n            return False\n\n        x, y = start\n        tx, ty = destination\n        visited = set()\n        return self.dfs(maze, x, y, tx, ty, visited)\n\n    def dfs(self, maze, x, y, tx, ty, visited):\n        if x == tx and y == ty:\n            return True\n        if (x, y) in visited:\n            return False\n\n        visited.add((x, y))\n\n        m, n = len(maze), len(maze[0])\n\n        for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):\n            _x = x + dx\n            _y = y + dy\n\n            while 0 <= _x < m and 0 <= _y < n and maze[_x][_y] == 0:\n                _x += dx\n                _y += dy\n\n            # since for now its means the position of wall\n            _x -= dx\n            _y -= dy\n\n            if self.dfs(maze, _x, _y, tx, ty, visited):\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/494_target_sum.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/target-sum/discuss/97334\n\nP: children used in positive,\nN: children used in negative,\nA: all children\n\nsum(P) - sum(N) = target\n=> sum(P) - sum(N) + sum(P) + sum(N) = target + sum(P) + sum(N)\n=> 2 * sum(P) = target + sum(A)\n=> sum(P) = (target + sum(A)) // 2\n=> find the subset sum\n\"\"\"\n\n\nclass Solution:\n    def findTargetSumWays(self, A, target):\n        \"\"\"\n        :type A: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not A:\n            return 0\n\n        _sum = sum(A)\n        if _sum < target or (_sum + target) % 2 == 1:\n            return 0\n\n        return self.subset_sum(A, (_sum + target) // 2)\n\n    def subset_sum(self, A, target):\n        \"\"\"\n        `dp[i]` means the number of ways\n        to make sum `i` using non-repeated children in `A`\n\n        `i` from `target` to `a - 1` => to make sure `i >= a`\n        \"\"\"\n        dp = [0] * (target + 1)\n        dp[0] = 1\n\n        for a in A:\n            for i in range(target, a - 1, -1):\n                dp[i] += dp[i - a]\n\n        return dp[target]\n"
  },
  {
    "path": "leetcode/499_the_maze_iii.py",
    "content": "class Solution:\n    \"\"\"\n    BFS\n    \"\"\"\n    def findShortestWay(self, maze, ball, hole):\n        \"\"\"\n        :type maze: List[List[int]]\n        :type ball: List[int]\n        :type hole: List[int]\n        :rtype: str\n\n        >>> s = Solution()\n        >>> maze = [[0, 0, 0, 0, 0],\n        ...         [1, 1, 0, 0, 1],\n        ...         [0, 0, 0, 0, 0],\n        ...         [0, 1, 0, 0, 1],\n        ...         [0, 1, 0, 0, 0]]\n\n        >>> s.findShortestWay(maze, [4, 3], [0, 1])\n        'lul'\n\n        >>> s.findShortestWay(maze, [4, 3], [3, 0])\n        'impossible'\n        \"\"\"\n        NOT_FOUND = 'impossible'\n\n        if not maze or not maze[0]:\n            return NOT_FOUND\n\n        m, n = len(maze), len(maze[0])\n        sx, sy = ball\n        tx, ty = hole\n        queue = [(sx, sy)]\n        paths = {(sx, sy): []}\n        distance = {(sx, sy): 0}\n\n        for x, y in queue:\n            for dx, dy, dn in (\n                (-1, 0, 'u'), (1, 0, 'd'),\n                (0, -1, 'l'), (0, 1, 'r'),\n            ):\n                _x = x + dx\n                _y = y + dy\n                _step = 0\n\n                while (\n                    0 <= _x < m and 0 <= _y < n and\n                    maze[_x][_y] == 0 and\n                    not (_x == tx and _y == ty)\n                ):\n                    _x += dx\n                    _y += dy\n                    _step += 1\n\n                if not (_x == tx and _y == ty):\n                    _x -= dx\n                    _y -= dy\n                    _step -= 1\n\n                if ((_x, _y) in distance and\n                    distance[x, y] + _step > distance[_x, _y]):\n                    continue\n\n                if ((_x, _y) in paths and\n                    paths[x, y] + [dn] > paths[_x, _y]):\n                    continue\n\n                distance[_x, _y] = distance[x, y] + _step\n                paths[_x, _y] = paths[x, y] + [dn]\n                queue.append((_x, _y))\n\n        return ''.join(paths[tx, ty]) if (tx, ty) in paths else NOT_FOUND\n\n\nimport heapq\n\n\nclass Solution2:\n    \"\"\"\n    Dijkstra\n    \"\"\"\n    def findShortestWay(self, maze, ball, hole):\n        \"\"\"\n        :type maze: List[List[int]]\n        :type ball: List[int]\n        :type hole: List[int]\n        :rtype: str\n\n        >>> s = Solution2()\n        >>> maze = [[0, 0, 0, 0, 0],\n        ...         [1, 1, 0, 0, 1],\n        ...         [0, 0, 0, 0, 0],\n        ...         [0, 1, 0, 0, 1],\n        ...         [0, 1, 0, 0, 0]]\n\n        >>> s.findShortestWay(maze, [4, 3], [0, 1])\n        'lul'\n\n        >>> s.findShortestWay(maze, [4, 3], [3, 0])\n        'impossible'\n        \"\"\"\n        NOT_FOUND = 'impossible'\n\n        if not maze or not maze[0]:\n            return NOT_FOUND\n\n        m, n = len(maze), len(maze[0])\n        sx, sy = ball\n        tx, ty = hole\n        heap = [(sx, sy)]\n        paths = {(sx, sy): []}\n        distance = {(sx, sy): 0}\n\n        while heap:\n            x, y = heapq.heappop(heap)\n\n            for dx, dy, dn in (\n                (-1, 0, 'u'), (1, 0, 'd'),\n                (0, -1, 'l'), (0, 1, 'r'),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                while (\n                    0 <= _x < m and 0 <= _y < n and\n                    maze[_x][_y] == 0 and\n                    not (_x == tx and _y == ty)\n                ):\n                    _x += dx\n                    _y += dy\n\n                if not (_x == tx and _y == ty):\n                    _x -= dx\n                    _y -= dy\n\n                _step = distance[x, y] + abs(_x - x) + abs(_y - y)\n\n                if (_x, _y) in distance and _step > distance[_x, _y]:\n                    continue\n\n                if (_x, _y) in paths and paths[x, y] + [dn] > paths[_x, _y]:\n                    continue\n\n                distance[_x, _y] = _step\n                paths[_x, _y] = paths[x, y] + [dn]\n                heapq.heappush(heap, (_x, _y))\n\n        return ''.join(paths[tx, ty]) if (tx, ty) in paths else NOT_FOUND\n"
  },
  {
    "path": "leetcode/505_the_maze_ii.py",
    "content": "class Solution:\n    \"\"\"\n    BFS\n    \"\"\"\n    def shortestDistance(self, maze, start, destination):\n        \"\"\"\n        :type maze: List[List[int]]\n        :type start: List[int]\n        :type destination: List[int]\n        :rtype: int\n\n        >>> s = Solution()\n        >>> maze = [[0, 0, 1, 0, 0],\n        ...         [0, 0, 0, 0, 0],\n        ...         [0, 0, 0, 1, 0],\n        ...         [1, 1, 0, 1, 1],\n        ...         [0, 0, 0, 0, 0]]\n\n        >>> s.shortestDistance(maze, [0, 4], [4, 4])\n        12\n\n        >>> s.shortestDistance(maze, [0, 4], [3, 2])\n        -1\n        \"\"\"\n        if not maze or not maze[0]:\n            return -1\n\n        m, n = len(maze), len(maze[0])\n        sx, sy = start\n        tx, ty = destination\n        queue = [(sx, sy)]\n        distance = {(sx, sy): 0}\n\n        for x, y in queue:\n            for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):\n                _x = x + dx\n                _y = y + dy\n                _step = 0\n\n                while 0 <= _x < m and 0 <= _y < n and maze[_x][_y] == 0:\n                    _x += dx\n                    _y += dy\n                    _step += 1\n\n                _x -= dx\n                _y -= dy\n\n                if ((_x, _y) in distance and\n                    distance[x, y] + _step >= distance[_x, _y]):\n                    continue\n\n                distance[_x, _y] = distance[x, y] + _step\n\n                if _x == tx and _y == ty:\n                    return distance[_x, _y]\n\n                queue.append((_x, _y))\n\n        return -1\n\n\n\n\nimport heapq\n\n\nclass Solution2:\n    \"\"\"\n    Dijkstra\n    \"\"\"\n    def shortestDistance(self, maze, start, destination):\n        \"\"\"\n        :type maze: List[List[int]]\n        :type start: List[int]\n        :type destination: List[int]\n        :rtype: int\n\n        >>> s = Solution2()\n        >>> maze = [[0, 0, 1, 0, 0],\n        ...         [0, 0, 0, 0, 0],\n        ...         [0, 0, 0, 1, 0],\n        ...         [1, 1, 0, 1, 1],\n        ...         [0, 0, 0, 0, 0]]\n\n        >>> s.shortestDistance(maze, [0, 4], [4, 4])\n        12\n\n        >>> s.shortestDistance(maze, [0, 4], [3, 2])\n        -1\n        \"\"\"\n        if not maze or not maze[0]:\n            return -1\n\n        m, n = len(maze), len(maze[0])\n        sx, sy = start\n        tx, ty = destination\n        heap = [(sx, sy)]\n        distance = {(sx, sy): 0}\n\n        while heap:\n            x, y = heapq.heappop(heap)\n\n            for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):\n                _x = x + dx\n                _y = y + dy\n\n                while 0 <= _x < m and 0 <= _y < n and maze[_x][_y] == 0:\n                    _x += dx\n                    _y += dy\n\n                _x -= dx\n                _y -= dy\n\n                _step = distance[x, y] + abs(_x - x) + abs(_y - y)\n\n                if (_x, _y) in distance and _step >= distance[_x, _y]:\n                    continue\n\n                if _x == tx and _y == ty:\n                    return _step\n\n                distance[_x, _y] = _step\n                heapq.heappush(heap, (_x, _y))\n\n        return -1\n"
  },
  {
    "path": "leetcode/518_coin_change_2.py",
    "content": "class Solution:\n    def change(self, amount, coins):\n        \"\"\"\n        :type amount: int\n        :type coins: List[int]\n        :rtype: int\n        \"\"\"\n        \"\"\"\n        `dp[a]` means the ways to make up amount `a`\n        \"\"\"\n        dp = [0] * (amount + 1)\n        dp[0] = 1  # the ways to make up `0` is just only 1\n\n        \"\"\"\n        iterate coin first, and then amount\n        otherwise it will add the dup ways in\n        re-count if `[1, 2]` and `[2, 1]`, but they are same\n        \"\"\"\n        for c in coins:\n            for a in range(c, amount + 1):\n                # if a < c: continue\n                dp[a] += dp[a - c]\n\n        return dp[amount]\n"
  },
  {
    "path": "leetcode/51_n_queens.py",
    "content": "class Solution:\n    def solveNQueens(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[List[str]]\n        \"\"\"\n        ans = []\n        if not n:\n            return ans\n\n        G = [['.'] * n for _ in range(n)]\n        self.dfs(G, 0, ans)\n        return ans\n\n    def dfs(self, G, y, ans):\n        if y == len(G):\n            ans.append(self.clone_board(G))\n            return\n\n        for x in range(len(G)):\n            if self.is_valid(G, x, y):\n                G[x][y] = 'Q'\n                self.dfs(G, y + 1, ans)\n                G[x][y] = '.'\n\n    def is_valid(self, G, x, y):\n        \"\"\"\n        traverse left half => i in [0, n], j in [0, y - 1] to\n        1. avoid `j == y` and speed up\n        and return False if\n        2. `x == i` => at same row\n        3. `x - i = y - j` => `x + j = y + i` => left diagonal line\n        4. `x - i = -(y - j)` => `x + y = i + j` => right diagonal line\n        \"\"\"\n        for i in range(len(G)):\n            for j in range(y):\n                if G[i][j] != 'Q':\n                    continue\n                if (x + j == y + i or\n                    x + y == i + j or\n                    x == i):\n                    return False\n        return True\n\n    def clone_board(self, G):\n        res = []\n        for R in G:\n            res.append(''.join(R))\n        return res\n"
  },
  {
    "path": "leetcode/524_longest_word_in_dictionary_through_deleting.py",
    "content": "class Solution:\n    \"\"\"\n    1. to check the word in list is subsequence of given s\n    2. ignoring if the length less than current ans\n    3. ignoring if the length equal current ans but has larger lexicographical order\n    \"\"\"\n    def findLongestWord(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: List[str]\n        :rtype: str\n        \"\"\"\n        ans = ''\n\n        for w in words:\n            if any((\n                not self.is_subseq(s, w),\n                len(w) < len(ans),\n                len(w) == len(ans) and w >= ans,  # means w has larger lexicographical order\n            )):\n                continue\n\n            ans = w\n\n        return ans\n\n    def is_subseq(self, s, t):\n        \"\"\"\n        return True if `t` is subsequence of `s`\n        \"\"\"\n        m, n = len(s), len(t)\n        i = j = 0\n\n        while i < m and j < n:\n            if s[i] == t[j]:\n                j += 1\n            i += 1\n\n        return j == n\n\n\nclass Solution:\n    \"\"\"\n    Brute Force: TLE\n    \"\"\"\n    def findLongestWord(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: List[str]\n        :rtype: str\n        \"\"\"\n        cands = []\n        self.find_cands(s, 0, cands, [])\n\n        ans = ''\n        target = set(words)\n\n        for w in cands:\n            if any((\n                w not in target,\n                len(w) < len(ans),\n                len(w) == len(ans) and w >= ans,\n            )):\n                continue\n\n            ans = w\n\n        return ans\n\n    def find_cands(self, s, i, cands, path):\n        if i == len(s):\n            cands.append(''.join(path))\n            return\n\n        # keep s[i]\n        path.append(s[i])\n        self.find_cands(s, i + 1, cands, path)\n        path.pop()\n\n        # ignore s[i]\n        self.find_cands(s, i + 1, cands, path)\n"
  },
  {
    "path": "leetcode/52_n_queens_ii.py",
    "content": "class Solution:\n    def totalNQueens(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        Xs = set()\n        DLs = set()  # left diagonal lines\n        DRs = set()  # right diagonal lines\n        return self.divide_conquer(n, 0, 0, Xs, DLs, DRs)\n\n    def divide_conquer(self, n, y, cnt, Xs, DLs, DRs):\n        for x in range(n):\n            if x in Xs:\n                continue\n\n            dl = x - y\n            if dl in DLs:\n                continue\n\n            dr = x + y\n            if dr in DRs:\n                continue\n\n            if y == n - 1:\n                cnt += 1\n                continue\n\n            Xs.add(x)\n            DLs.add(dl)\n            DRs.add(dr)\n            cnt = self.divide_conquer(n, y + 1, cnt, Xs, DLs, DRs)\n            Xs.discard(x)\n            DLs.discard(dl)\n            DRs.discard(dr)\n\n        return cnt\n"
  },
  {
    "path": "leetcode/530_minimum_absolute_difference_in_bst.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    time: O(n)\n    space: O(1)\n    \"\"\"\n    ans = float('inf')\n    pre = None\n\n    def getMinimumDifference(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return self.ans\n\n        self.getMinimumDifference(root.left)\n\n        if self.pre and root.val - self.pre.val < self.ans:\n            self.ans = root.val - self.pre.val\n\n        self.pre = root\n\n        self.getMinimumDifference(root.right)\n        return self.ans\n"
  },
  {
    "path": "leetcode/542_01_matrix.py",
    "content": "class Solution:\n    def updateMatrix(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return []\n\n        m, n = len(matrix), len(matrix[0])\n        ans = [[float('inf')] * n for _ in range(m)]\n        queue = []\n\n        for x in range(m):\n            for y in range(n):\n                if matrix[x][y] == 0:\n                    ans[x][y] = 0\n                    queue.append((x, y))\n\n        for x, y in queue:\n            for dx, dy in (\n                (-1, 0), (1, 0),\n                (0, -1), (0, 1),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if ans[_x][_y] < ans[x][y] + 1:\n                    continue\n\n                ans[_x][_y] = ans[x][y] + 1\n                queue.append((_x, _y))\n\n        return ans\n"
  },
  {
    "path": "leetcode/54_spiral_matrix.py",
    "content": "class Solution:\n    def spiralOrder(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not matrix or not matrix[0]:\n            return ans\n\n        # need keep its order to go right, bottom, left, top\n        delta = (\n            (0, 1), (1, 0),\n            (0, -1), (-1, 0),\n        )\n        m, n = len(matrix), len(matrix[0])\n        x = y = turn = 0\n\n        for _ in range(m * n):\n            ans.append(matrix[x][y])\n            matrix[x][y] = None\n            _x = x + delta[turn][0]\n            _y = y + delta[turn][1]\n\n            if not (0 <= _x < m and 0 <= _y < n) or matrix[_x][_y] is None:\n                turn = (turn + 1) % len(delta)\n                _x = x + delta[turn][0]\n                _y = y + delta[turn][1]\n\n            x = _x\n            y = _y\n\n        return ans\n"
  },
  {
    "path": "leetcode/592_fraction_addition_and_subtraction.py",
    "content": "import re\n\n\nclass Solution:\n    def fractionAddition(self, E):\n        \"\"\"\n        :type E: str\n        :rtype: str\n        \"\"\"\n        S = []  # signs\n\n        if E[0] != '-':\n            S.append('+')\n\n        for c in E:\n            if c == '+' or c == '-':\n                S.append(c)\n\n        a, b = 0, 1\n        i = 0\n        for frac in re.split('\\+|-', E):\n            if not frac:\n                continue\n\n            _a, _b = frac.split('/')\n            _a = int(_a)\n            _b = int(_b)\n\n            # if needs to prevent overflow, `// gcd`\n            if S[i] == '+':\n                a = a * _b + _a * b\n            else:\n                a = a * _b - _a * b\n\n            b = b * _b\n\n            gcd = self.get_gcd(a, b)\n            a //= gcd\n            b //= gcd\n\n            i += 1\n\n        return '{}/{}'.format(a, b)\n\n    def get_gcd(self, a, b):\n        while b:\n            a, b = b, a % b\n        return a\n"
  },
  {
    "path": "leetcode/593_valid_square.py",
    "content": "class Solution:\n    def validSquare(self, p1, p2, p3, p4):\n        \"\"\"\n        :type p1: List[int]\n        :type p2: List[int]\n        :type p3: List[int]\n        :type p4: List[int]\n        :rtype: bool\n        \"\"\"\n        ps = []\n\n        for p in (p1, p2, p3, p4):\n            if not p:\n                return False\n\n            ps.append(p)\n\n        ps.sort()\n\n        # 0: lb, 1: lt, 2:rb, 3: rt\n        l01 = self.get_distance(ps[0], ps[1])\n        l02 = self.get_distance(ps[0], ps[2])\n        l13 = self.get_distance(ps[1], ps[3])\n        l23 = self.get_distance(ps[2], ps[3])\n\n        l03 = self.get_distance(ps[0], ps[3])\n        l12 = self.get_distance(ps[1], ps[2])\n\n        return all((\n            l01 == l02 == l13 == l23 > 0,\n            l03 == l12,\n        ))\n\n    def get_distance(self, a, b):\n        \"\"\"\n        find the size of 'ab'\n        \"\"\"\n        dx = a[0] - b[0]\n        dy = a[1] - b[1]\n        return (dx * dx + dy * dy) ** 0.5\n"
  },
  {
    "path": "leetcode/59_spiral_matrix_ii.py",
    "content": "class Solution:\n    def generateMatrix(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[List[int]]\n        \"\"\"\n        if not n or n < 1:\n            return []\n        if n == 1:\n            return [[1]]\n\n        ans = [[0] * n for _ in range(n)]\n        delta = (\n            (0, 1), (1, 0),\n            (0, -1), (-1, 0),\n        )\n        x = y = turn = 0\n\n        for i in range(1, n * n + 1):\n            ans[x][y] = i\n            _x = x + delta[turn][0]\n            _y = y + delta[turn][1]\n\n            if not (0 <= _x < n and 0 <= _y < n) or ans[_x][_y] != 0:\n                turn = (turn + 1) % len(delta)\n                _x = x + delta[turn][0]\n                _y = y + delta[turn][1]\n\n            x = _x\n            y = _y\n\n        return ans\n"
  },
  {
    "path": "leetcode/5_longest_palindromic_substring.py",
    "content": "class Solution:\n    def longestPalindrome(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        if not s:\n            return ''\n\n        start = size = 0\n\n        for i in range(len(s)):\n            _start, _size = self.check_palindrome(s, i, i)\n\n            if _size > size:\n                size = _size\n                start = _start\n\n            _start, _size = self.check_palindrome(s, i, i + 1)\n\n            if _size > size:\n                size = _size\n                start = _start\n\n        return s[start:start + size]\n\n    def check_palindrome(self, s, left, right):\n        n = len(s)\n\n        while left >= 0 and right < n and s[left] == s[right]:\n            left -= 1\n            right += 1\n\n        return left + 1, right - left - 1\n"
  },
  {
    "path": "leetcode/616_add_bold_tag_in_string.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for s in (Solution(),):\n...     for _in, _out in (\n...         (('', ['']), ''),\n...         (('abcxyz123', ['abc', '123']), '<b>abc</b>xyz<b>123</b>'),\n...         (('aaabbcc', ['aaa','aab','bc']), '<b>aaabbc</b>c'),\n...         (('aabcd', ['ab', 'bc']), 'a<b>abc</b>d'),\n...     ):\n...         res = s.addBoldTag(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    def addBoldTag(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: List[str]\n        :rtype: str\n        \"\"\"\n        if not s or not words:\n            return ''\n\n        TMPL = '<b>{}</b>'\n        n = len(s)\n        ans = []\n        is_bold = [False] * n\n        left = right = 0\n\n        for left in range(n):\n            for w in words:\n                size = len(w)\n\n                if s[left:left + size] == w and left + size > right:\n                    right = left + size\n\n            is_bold[left] = right > left\n\n        left = right = 0\n\n        while left < n:\n            if not is_bold[left]:\n                ans.append(s[left])\n                left += 1\n                continue\n\n            right = left\n\n            while right < n and is_bold[right]:\n                right += 1\n\n            ans.append(TMPL.format(s[left:right]))\n            left = right  # imply left' = left + 1\n\n        return ''.join(ans)\n"
  },
  {
    "path": "leetcode/643_maximum_average_subarray_i.py",
    "content": "class Solution:\n    def findMaxAverage(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: float\n        \"\"\"\n        \"\"\"\n        Assuming the answer we want is `Ans = Max(A[i] + A[i+1] + ... + A[i+k-1])`,\n        and we define the `P[i] = A[0] + A[1] + ... + A[i-1]`,\n        so that `Ans = Max(P[i+k] - P[i])`, and `i+k-1 < n -> i < n-k+1`\n        * max index in P is `i+k`, so in A is `(i+k)-1`, `i+k-1 < n`\n        \"\"\"\n        \"\"\"\n        P[0] = 0\n        P[1] = P[0] + A[0]\n        P[2] = P[1] + A[1]\n        P[i] = P[i-1] + A[i-1]\n             = A[0] + A[1] + ... + A[i-1]\n        \"\"\"\n        P = [0]\n        for x in nums: P.append(P[-1] + x)\n        max_sum = max(P[i+k] - P[i] for i in range(len(nums) - k + 1))\n        return max_sum / float(k)\n\nclass Solution:\n    def findMaxAverage(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: float\n        \"\"\"\n        \"\"\"\n        Assuming k = 3\n        i: 0 1 2 3\n              |--> Start to find max sum\n                |--> Start to remove past child\n        \"\"\"\n        max_sum, tmp_sum = float('-inf'), 0\n        for i in range(len(nums)):\n            tmp_sum += nums[i]\n            if i >= k:\n                tmp_sum -= nums[i-k]\n            if i + 1 >= k:\n                max_sum = max(max_sum, tmp_sum)\n        return max_sum / float(k)\n"
  },
  {
    "path": "leetcode/66_plus_one.py",
    "content": "class Solution:\n    def plusOne(self, digits):\n        \"\"\"\n        :type digits: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not digits:\n            return ans\n\n        carry = 1\n\n        for i in range(len(digits) - 1, -1, -1):\n            carry += digits[i]\n            ans.append(carry % 10)\n            carry //= 10\n\n        if carry:\n            ans.append(carry)\n\n        ans.reverse()\n\n        return ans\n\n\nclass Solution:\n    def plusOne(self, digits):\n        \"\"\"\n        :type digits: List[int]\n        :rtype: List[int]\n        \"\"\"\n        if not digits:\n            return []\n\n        carry = 0\n        digits[-1] += 1\n\n        for i in range(len(digits) - 1, -1, -1):\n            carry += digits[i]\n            digits[i] = carry % 10\n            carry //= 10\n\n        if carry:\n            digits.append(carry)\n\n            for i in range(len(digits) - 1, 0, -1):\n                digits[i], digits[i - 1] = digits[i - 1], digits[i]\n\n        return digits\n"
  },
  {
    "path": "leetcode/676_implement_magic_dictionary.py",
    "content": "\"\"\"\nYour MagicDictionary object will be instantiated and called as such:\nobj = MagicDictionary()\nobj.buildDict(dict)\nparam_2 = obj.search(word)\n\"\"\"\n\n\nclass MagicDictionary:\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.words = collections.defaultdict(set)\n\n    def buildDict(self, words):\n        \"\"\"\n        Build a dictionary through a list of words\n        :type words: List[str]\n        :rtype: void\n        \"\"\"\n        for word in words:\n            for i in range(len(word)):\n                key = '{0},{1}'.format(word[:i], word[i + 1:])\n\n                if key not in self.words:\n                    self.words[key] = set()\n\n                # add char to distinct word if its same\n                self.words[key].add(word[i])\n\n    def search(self, word):\n        \"\"\"\n        Returns if there is any word in the trie that equals to the given word after modifying exactly one character\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        for i in range(len(word)):\n            key = '{0},{1}'.format(word[:i], word[i + 1:])\n\n            if key not in self.words:\n                continue\n\n            words = self.words[key]\n\n            # 1. word[i] not in words => means not same word\n            # 2. len(words) > 1 => if got same but still can mapping other\n            if word[i] not in words or len(words) > 1:\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/679_24_game.py",
    "content": "class Solution:\n    EPS = 1e-6\n    OP = (\n        lambda a, b: a + b,\n        lambda a, b: a * b,\n        lambda a, b: a - b,\n        lambda a, b: a / b,\n    )\n\n    def judgePoint24(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return False\n\n        n = len(nums)\n\n        if n == 1:\n            return abs(nums[0] - 24) < self.EPS\n\n        for i in range(n):\n            for j in range(n):\n                if i == j:\n                    continue\n\n                nxts = [nums[k] for k in range(n) if i != k != j]  # i != j != k is different\n\n                for k in range(len(self.OP)):\n                    if i < j and k < 2:\n                        # since a + b == b + a, so just do half in j >= i\n                        # same for `*`\n                        continue\n                    if nums[j] == 0 and k == 3:\n                        # divide by 0\n                        continue\n\n                    nxts.append(self.OP[k](nums[i], nums[j]))\n\n                    if self.judgePoint24(nxts):\n                        return True\n\n                    nxts.pop()\n\n        return False\n"
  },
  {
    "path": "leetcode/681_next_closest_time.py",
    "content": "\"\"\"\nit's very similar with `next permutation`\njust a `next combination`\n\n1. `digits` save unique num and in order\n2. `ids` record current used num\n3. keep doing plus one and check valid\n\n>>> gotcha = []\n>>> s = Solution()\n>>> for _in, _out in (\n...     ('19:34', '19:39'), ('23:59', '22:22'),\n...     ('22:22', '22:22'), ('24:24', ''),\n...     ('23:23', '23:32'), ('12:34', '12:41'),\n...     ('00:00', '00:00'), ('01:32', '01:33'),\n... ):\n...     res = s.nextClosestTime(_in)\n...     if res != _out: print('in: {}, out: {}, exp: {}'.format(_in, res, _out))\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    def nextClosestTime(self, time):\n        \"\"\"\n        :type time: str\n        :rtype: str\n        \"\"\"\n        if not (\n            time and len(time) == 5 and time[2] == ':' and\n            0 <= int(time[:2]) < 24 and 0 <= int(time[3:]) < 60\n        ):\n            return ''\n\n        times = [int(t) for t in time if t != ':']\n        digits = []\n\n        for a in sorted(times):\n            if digits and a == digits[-1]:\n                continue\n\n            digits.append(a)\n\n        ids = [digits.index(t) for t in times]\n        ids[-1] += 1\n\n        while not self.is_valid(ids, digits):\n            ids[-1] += 1\n\n        h = digits[ids[0]] * 10 + digits[ids[1]]\n        m = digits[ids[2]] * 10 + digits[ids[3]]\n\n        return '{}:{}'.format(\n            '0' + str(h) if h < 10 else str(h),\n            '0' + str(m) if m < 10 else str(m)\n        )\n\n    def is_valid(self, ids, digits):\n        n = len(digits)\n        carry = 0\n        i = len(ids) - 1\n\n        while i >= 0:\n            carry += ids[i]\n            ids[i] = carry % n\n            carry = carry // n\n            i -= 1\n\n        if carry:\n            ids[:] = [0] * len(ids)\n            return True\n\n        h = digits[ids[0]] * 10 + digits[ids[1]]\n        m = digits[ids[2]] * 10 + digits[ids[3]]\n\n        if 0 <= h < 24 and 0 <= m < 60:\n            return True\n\n        return False\n"
  },
  {
    "path": "leetcode/682_baseball_game.py",
    "content": "class Solution:\n    def calPoints(self, ops):\n        \"\"\"\n        :type ops: List[str]\n        :rtype: int\n        \"\"\"\n        if not ops:\n            return 0\n\n        stack = []\n\n        for op in ops:\n            if op == 'C':\n                stack.pop()\n            elif op == 'D':\n                stack.append(2 * stack[-1])\n            elif op == '+':\n                stack.append(stack[-1] + stack[-2])\n            else:\n                stack.append(int(op))\n\n        return sum(stack)\n"
  },
  {
    "path": "leetcode/683_k_empty_slots.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for s in (Solution(), Solution2()):\n...     for _in, _out in (\n...         (([1,3,2], 1), 2),\n...         (([1,2,3], 1), -1),\n...     ):\n...         res = s.kEmptySlots(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\nimport bisect\n\n\nclass Solution:\n    \"\"\"\n    Maintain pos by bloom order\n    \"\"\"\n    def kEmptySlots(self, flowers, k):\n        \"\"\"\n        :type flowers: List[int]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        bloom = []\n\n        for day in range(len(flowers)):\n            x = flowers[day]\n            i = bisect.bisect_left(bloom, x)\n            for _x in bloom[max(0, i - 1):i + 1]:\n                if abs(_x - x) - 1 == k:\n                    return day + 1  # changed to 1-based\n            bloom.insert(i, x)\n\n        return -1\n\n\nclass Solution2:\n    \"\"\"\n    Two Pointer:\n    https://blog.csdn.net/magicbean2/article/details/79235465\n    \"\"\"\n    def kEmptySlots(self, flowers, k):\n        \"\"\"\n        :type flowers: List[int]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        n = len(flowers)\n        x2day = [0] * n\n        for day in range(n):\n            \"\"\"\n            day: 0-based => 1-based\n            x:   1-based => 0-based\n            \"\"\"\n            x = flowers[day]\n            x2day[x - 1] = day + 1\n\n        ans = INF = float('inf')\n        left, right = 0, k + 1\n        i = 0\n\n        while right < n:\n            if any((\n                x2day[i] < x2day[left],\n                x2day[i] <= x2day[right],\n            )):\n                if i == right:\n                    ans = min(ans, max(x2day[left], x2day[right]))\n                left, right = i, k + i + 1\n            i += 1\n\n        return ans if ans < INF else -1\n"
  },
  {
    "path": "leetcode/684_redundant_connection.py",
    "content": "\"\"\"\ngiven input is an undirected graph\n\n1. iterate edges\n2. if u and v are connected before we add edge in nodes (graph)\n   => that is the edge should be removed\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    UnionFind\n    \"\"\"\n    def findRedundantConnection(self, edges):\n        \"\"\"\n        :type edges: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        if not edges:\n            return []\n\n        nodes = {}\n\n        for u, v in edges:\n            if not self.union(nodes, u, v):\n                return [u, v]\n\n        return []\n\n    def union(self, nodes, u, v):\n        a = self.find(nodes, u)\n        b = self.find(nodes, v)\n\n        if a == b:\n            return False\n\n        nodes[a] = b\n        return True\n\n    def find(self, nodes, u):\n        if u not in nodes:\n            nodes[u] = u\n            return u\n        if nodes[u] == u:\n            return u\n\n        nodes[u] = self.find(nodes, nodes[u])\n        return nodes[u]\n\n\nimport collections\n\n\nclass Solution:\n    \"\"\"\n    DFS\n    \"\"\"\n    def findRedundantConnection(self, edges):\n        \"\"\"\n        :type edges: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        if not edges:\n            return []\n\n        nodes = collections.defaultdict(set)\n\n        for u, v in edges:\n            # dfs to check u and v are connected already => cycle\n            if u in nodes and v in nodes and self.dfs(nodes, u, v, set()):\n                return [u, v]\n\n            nodes[u].add(v)\n            nodes[v].add(u)\n\n        return []\n\n    def dfs(self, nodes, u, v, visited):\n        if u == v:\n            return True\n        if u in visited:\n            return False\n\n        visited.add(u)\n\n        for x in nodes[u]:\n            if self.dfs(nodes, x, v, visited):\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/685_redundant_connection_ii.py",
    "content": "\"\"\"\ngiven input is an directed graph\n\n3 corner cases:\n\n1. There is a loop in the graph, and no vertex has more than 1 parent.\n2. A vertex has more than 1 parent, but there isn’t a loop in the graph.\n3. A vertex has more than 1 parent, and is part of a loop.\n\nREF: https://leetcode.com/problems/redundant-connection-ii/discuss/108070/Python-O(N)-concise-solution-with-detailed-explanation-passed-updated-testcases\n\"\"\"\n\n\nimport collections\n\n\nclass Solution:\n    def findRedundantDirectedConnection(self, edges):\n        \"\"\"\n        :type edges: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        ans = edge = None  # `edge` is the last edge in a loop\n        adj = collections.defaultdict(set)\n        uf = collections.defaultdict(int)\n        has_parent = set()\n\n        for u, v in edges:\n            adj[u].add(v)\n\n            if v in has_parent:\n                ans = (u, v)\n\n            if not self.union(uf, u, v):\n                edge = (u, v)\n\n            has_parent.add(v)\n\n        if not ans:\n            return edge\n\n        res = self.dfs(ans[1], adj, set())\n        return res if res else ans\n\n    def union(self, uf, u, v):\n        a = self.find(uf, u)\n        b = self.find(uf, v)\n\n        if a == b:\n            return False\n\n        uf[b] = a\n        return True\n\n    def find(self, uf, u):\n        if uf[u] == 0:\n            uf[u] = u\n            return u\n        if uf[u] == u:\n            return u\n\n        uf[u] = self.find(uf, uf[u])\n        return uf[u]\n\n    def dfs(self, u, adj, visited):\n        # to detect cycle\n        visited.add(u)\n\n        for v in adj[u]:\n            if v in visited:\n                return (u, v)\n\n            res = self.dfs(v, adj, visited)\n            if res:\n                return res\n"
  },
  {
    "path": "leetcode/688_knight_probability_in_chessboard.py",
    "content": "import collections\n\n\nclass Solution:\n    \"\"\"\n    DP:\n    1. init the first pos as 1\n    2. keep simulate the process and divide the probability\n    3. sum the values\n    \"\"\"\n    def knightProbability(self, n, k, r, c):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :type r: int\n        :type c: int\n        :rtype: float\n        \"\"\"\n        dp = collections.defaultdict(int)\n        dp[r, c] = 1.0\n\n        for _ in range(k):\n            nxt = collections.defaultdict(int)\n\n            for x in range(n):\n                for y in range(n):\n                    for dx, dy in (\n                        (-1, -2),\n                        ( 1, -2),\n                        (-2, -1),\n                        ( 2, -1),\n                        (-2,  1),\n                        ( 2,  1),\n                        (-1,  2),\n                        ( 1,  2),\n                    ):\n                        _x = x + dx\n                        _y = y + dy\n\n                        if not (0 <= _x < n and 0 <= _y < n):\n                            continue\n\n                        nxt[_x, _y] += dp[x, y] / 8.0\n\n            dp = nxt\n\n        return sum(dp.values())\n\n\nclass Solution:\n    \"\"\"\n    BFS: TLE\n    \"\"\"\n    def knightProbability(self, n, k, r, c):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :type r: int\n        :type c: int\n        :rtype: float\n        \"\"\"\n        if n == 1 and k == 0:\n            return 1.0\n\n        queue, _queue = [(r, c)], []\n        total = 8 ** k\n        valid = 0\n\n        while queue and k:\n            k -= 1\n\n            for x, y in queue:\n                for dx, dy in (\n                    (-1, -2),\n                    ( 1, -2),\n                    (-2, -1),\n                    ( 2, -1),\n                    (-2,  1),\n                    ( 2,  1),\n                    (-1,  2),\n                    ( 1,  2),\n                ):\n                    _x = x + dx\n                    _y = y + dy\n\n                    if not (0 <= _x < n and 0 <= _y < n):\n                        continue\n\n                    if k == 0:\n                        valid += 1\n\n                    if k > 0:\n                        _queue.append((_x, _y))\n\n            queue, _queue = _queue, []\n\n        return valid / total\n"
  },
  {
    "path": "leetcode/689_maximum_sum_of_3_non_overlapping_subarrays.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/discuss/108231\n\"\"\"\n\n\nclass Solution:\n    def maxSumOfThreeSubarrays(self, A, k):\n        \"\"\"\n        :type A: List[int]\n        :type k: int\n        :rtype: List[int]\n        \"\"\"\n        ans = [-1] * 3\n        if not A or len(A) < 3 * k:\n            return ans\n\n        n = len(A)\n        S = [0] * (n + 1)  # prefix sum\n        L = [0] * n  # the starting index of the maximum interval sum with length k in [0, i]\n        R = [n - k] * n  # the starting index of the maximum interval sum with length k in [i, n - 1]\n\n        for i in range(1, n + 1):\n            S[i] = S[i - 1] + A[i - 1]\n\n        max_sum = S[k] - S[0]  # maximum interval sum\n        _sum = 0\n        for i in range(k, n):\n            L[i] = L[i - 1]\n            _sum = S[i + 1] - S[i + 1 - k]\n            if _sum > max_sum:\n                L[i] = i + 1 - k\n                max_sum = _sum\n\n        max_sum = S[n] - S[n - k]\n        _sum = 0\n        for i in range(n - k - 1, -1, -1):\n            R[i] = R[i + 1]\n            _sum = S[i + k] - S[i]\n            if _sum >= max_sum:\n                R[i] = i\n                max_sum = _sum\n\n        max_sum = _sum = 0\n        for i in range(k, n - 2 * k + 1):\n            left = L[i - 1]\n            right = R[i + k]\n            _sum = S[i + k] - S[i] + S[left + k] - S[left] + S[right + k] - S[right]\n            if _sum > max_sum:\n                max_sum = _sum\n                ans[:] = left, i, right\n\n        return ans\n"
  },
  {
    "path": "leetcode/697_degree_of_an_array.py",
    "content": "class Solution:\n    def findShortestSubArray(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        if not A:\n            return 0\n\n        n = len(A)\n        L, R, C = {}, {}, {}\n        for i in range(n):\n            if A[i] not in L:\n                L[A[i]] = i\n            R[A[i]] = i\n            C[A[i]] = C.get(A[i], 0) + 1\n\n        ans = len(A)\n        degree = max(C.values())\n        for a, c in C.items():\n            if c == degree and R[a] - L[a] + 1 < ans:\n                ans = R[a] - L[a] + 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/719_find_k_th_smallest_pair_distance.py",
    "content": "class Solution:\n    def smallestDistancePair(self, A, k):\n        \"\"\"\n        :type A: List[int]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        if not A or not k:\n            return -1\n\n        A.sort()\n\n        left, right = 0, A[-1] - A[0]\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if self.check_valid(A, mid, k):\n                right = mid\n            else:\n                left = mid\n\n        return left if self.check_valid(A, left, k) else right\n\n    def check_valid(self, A, mid, k):\n        \"\"\"\n        valid if there are at least `k` pairs when distance is `mid`\n        \"\"\"\n        cnt = left = 0\n\n        for right in range(len(A)):\n            while A[right] - A[left] > mid:\n                left += 1\n\n            cnt += right - left\n\n            if cnt >= k:\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/721_accounts_merge.py",
    "content": "class Solution:\n    def accountsMerge(self, A):\n        \"\"\"\n        :type A: List[List[str]]\n        :rtype: List[List[str]]\n        \"\"\"\n        if not A:\n            return []\n\n        M = {}  # mails\n        M2N = {}  # mail to name\n        for L in A:\n            for i in range(1, len(L)):\n                M2N[L[i]] = L[0]\n                self.connect(M, L[i], L[1])\n\n        for a in M:\n            self.find(M, a)\n\n        res = {}\n        for m1, m0 in M.items():\n            if m0 not in res:\n                res[m0] = []\n\n            res[m0].append(m1)\n\n        return [[M2N[m]] + sorted(M) for m, M in res.items()]\n\n    def connect(self, N, a, b):\n        _a = self.find(N, a)\n        _b = self.find(N, b)\n\n        if _a is not _b:\n            N[_a] = _b\n\n    def find(self, N, a):\n        if a not in N:\n            N[a] = a\n            return a\n        if N[a] is a:\n            return a\n\n        N[a] = self.find(N, N[a])\n        return N[a]\n"
  },
  {
    "path": "leetcode/734_sentence_similarity.py",
    "content": "\"\"\"\n>>> pairs = [['great', 'fine'], ['acting', 'drama'], ['skills', 'talent']]\n>>> gotcha = []\n>>> s = Solution()\n>>> for _in, _out in (\n...     ((['great', 'acting'], ['fine', 'drama'], pairs), True),\n...     ((['great', 'acting'], ['fine', 'talent'], pairs), False),\n...     ((['great'], ['great'], []), True),\n...     ((['great'], ['fine', 'drama'], pairs), False),\n... ):\n...     res = s.areSentencesSimilar(*_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nimport collections\n\n\nclass Solution:\n    def areSentencesSimilar(self, words1, words2, pairs):\n        \"\"\"\n        :type words1: List[str]\n        :type words2: List[str]\n        :type pairs: List[List[str]]\n        :rtype: bool\n        \"\"\"\n        if len(words1) != len(words2):\n            return False\n\n        simils = collections.defaultdict(set)\n\n        for a, b in pairs:\n            simils[a].add(b)\n            simils[b].add(a)\n\n        for i in range(len(words1)):\n            a = words1[i]\n            b = words2[i]\n\n            if a != b and b not in simils[a]:\n                return False\n\n        return True\n"
  },
  {
    "path": "leetcode/737_sentence_similarity_ii.py",
    "content": "\"\"\"\n>>> pairs = [['great', 'fine'], ['acting', 'drama'], ['skills', 'talent']]\n>>> gotcha = []\n>>> for s in (Solution(), Solution2()):\n...     for _in, _out in (\n...         ((['great', 'acting'], ['fine', 'drama'], pairs), True),\n...         ((['great', 'acting'], ['fine', 'talent'], pairs), False),\n...         ((['great'], ['great'], []), True),\n...         ((['great'], ['fine', 'drama'], pairs), False),\n...     ):\n...         res = s.areSentencesSimilarTwo(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    UnionFind\n    \"\"\"\n    def areSentencesSimilarTwo(self, words1, words2, pairs):\n        \"\"\"\n        :type words1: List[str]\n        :type words2: List[str]\n        :type pairs: List[List[str]]\n        :rtype: bool\n        \"\"\"\n        if len(words1) != len(words2):\n            return False\n\n        nodes = {}\n\n        for a, b in pairs:\n            self.union(nodes, a, b)\n\n        for i in range(len(words1)):\n            a = words1[i]\n            b = words2[i]\n            _a = self.find(nodes, a)\n            _b = self.find(nodes, b)\n\n            if a != b and _a != _b:\n                return False\n\n        return True\n\n    def union(self, nodes, a, b):\n        _a = self.find(nodes, a)\n        _b = self.find(nodes, b)\n\n        if _a is not _b:\n            nodes[_a] = _b\n\n        return _b\n\n    def find(self, nodes, a):\n        if a not in nodes:\n            nodes[a] = a\n            return a\n        if nodes[a] is a:\n            return a\n\n        nodes[a] = self.find(nodes, nodes[a])\n        return nodes[a]\n\n\nimport collections\n\n\nclass Solution2:\n    \"\"\"\n    DFS\n    \"\"\"\n    def areSentencesSimilarTwo(self, words1, words2, pairs):\n        \"\"\"\n        :type words1: List[str]\n        :type words2: List[str]\n        :type pairs: List[List[str]]\n        :rtype: bool\n        \"\"\"\n        if len(words1) != len(words2):\n            return False\n\n        simils = collections.defaultdict(set)\n\n        for a, b in pairs:\n            simils[a].add(b)\n            simils[b].add(a)\n\n        for i in range(len(words1)):\n            a = words1[i]\n            b = words2[i]\n\n            if a != b and not self.dfs(a, b, simils, set()):\n                return False\n\n        return True\n\n    def dfs(self, start, end, simils, path):\n        # check start and end are connected\n        if start == end:\n            return True\n        if start not in simils or start in path:\n            return False\n\n        path.add(start)\n\n        for nxt in simils[start]:\n            if nxt in path:\n                continue\n\n            res = self.dfs(nxt, end, simils, path)\n            if res:\n                return True\n\n        path.discard(start)\n        return False\n"
  },
  {
    "path": "leetcode/744_find_smallest_letter_greater_than_target.py",
    "content": "class Solution:\n    def nextGreatestLetter(self, L, target):\n        \"\"\"\n        :type L: List[str]\n        :type target: str\n        :rtype: str\n        \"\"\"\n        n = len(L)\n        left, right = 0, n - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if L[mid] <= target:\n                left = mid\n            else:\n                right = mid\n\n        if target < L[left]:\n            return L[left]\n\n        if target < L[right]:\n            return L[right]\n\n        return L[0]\n"
  },
  {
    "path": "leetcode/746_min_cost_climbing_stairs.py",
    "content": "class Solution:\n    def minCostClimbingStairs(self, cost):\n        \"\"\"\n        :type cost: List[int]\n        :rtype: int\n        \"\"\"\n\n        if not cost:\n            return 0\n\n        n = len(cost)\n\n        \"\"\"\n        `dp[i]` means the min cost to possible to reach previous `i` steps\n        \"\"\"\n        dp = [0] * (n + 1)\n\n        for i in range(2, n + 1):\n            \"\"\"\n            If you decide to come from some step,\n            and then pay the fee to the from step\n            \"\"\"\n            dp[i] = min(\n                dp[i - 1] + cost[i - 1],\n                dp[i - 2] + cost[i - 2]\n            )\n\n        return dp[n]\n"
  },
  {
    "path": "leetcode/747_largest_number_at_least_twice_of_others.py",
    "content": "class Solution:\n    def dominantIndex(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n\n        _max = __max = float('-inf')\n        _max_i = -1\n\n        for i in range(len(A)):\n            if A[i] > _max:\n                __max = _max\n                _max = A[i]\n                _max_i = i\n                continue\n\n            if A[i] > __max:\n                __max = A[i]\n\n        if _max >= __max * 2:\n            return _max_i\n\n        return -1\n"
  },
  {
    "path": "leetcode/748_shortest_completing_word.py",
    "content": "class Solution:\n    def shortestCompletingWord(self, P, words):\n        \"\"\"\n        :type P: str\n        :type words: List[str]\n        :rtype: str\n        \"\"\"\n\n        ans = ''\n        if not P or not words:\n            return ans\n\n        p_times = self.get_times(P)\n        _min_size = float('inf')\n\n        for word in words:\n            times = self.get_times(word)\n            if len(word) < _min_size and self.is_included(p_times, times):\n                ans = word\n                _min_size = len(word)\n\n        return ans\n\n    def is_included(self, a_times, b_times):\n        \"\"\"True if A is a subset of B\"\"\"\n        for char, times in a_times.items():\n            if char not in b_times:\n                return False\n\n            if b_times[char] < times:\n                return False\n\n        return True\n\n    def get_times(self, word):\n        times = {}\n        ord_a = ord('a')\n        ord_z = ord('z')\n\n        for char in word.lower():\n            if ord_a <= ord(char) <= ord_z:\n                times[char] = times.get(char, 0) + 1\n\n        return times\n"
  },
  {
    "path": "leetcode/749_contain_virus.py",
    "content": "\"\"\"\nTest Case:\n\n[[1,1,1], [1,0,1], [1,1,1]]\n\n[[1,1,1,0,0,0,0,0,0], [1,0,1,0,1,1,1,1,1], [1,1,1,0,0,0,0,0,0]]\n\n# In the process of spreading will intersect\n[[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,1,0,0],[1,0,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,1,0,0,0],[0,0,0,0,0,0,1,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,1,0],[0,0,0,0,1,0,1,0,0,0],[0,0,0,0,0,0,0,0,0,0]]\n\n# needs to dedup `ex_virus` and `spreading`\n[[0,1,0,1,1,1,1,1,1,0],[0,0,0,1,0,0,0,0,0,0],[0,0,1,1,1,0,0,0,1,0],[0,0,0,1,1,0,0,1,1,0],[0,1,0,0,1,0,1,1,0,1],[0,0,0,1,0,1,0,1,1,1],[0,1,0,0,1,0,0,1,1,0],[0,1,0,1,0,0,0,1,1,0],[0,1,1,0,0,1,1,0,0,1],[1,0,1,1,0,1,0,1,0,1]]\n\"\"\"\n\n\nclass Solution:\n    NORMAL = 0\n    VIRUS = 1\n    EX_VIRUS = -1\n\n    V = (\n        (-1,  0),\n        ( 1,  0),\n        ( 0, -1),\n        ( 0,  1),\n    )\n\n    def containVirus(self, G):\n        \"\"\"\n        :type G: List[List[int]]\n        :rtype: int\n        \"\"\"\n\n        walls = 0\n\n        if not G or not G[0]:\n            return walls\n\n        while True:\n            _walls = self.build_walls(G)\n            if _walls == 0:\n                break\n            walls += _walls\n\n        return walls\n\n    def build_walls(self, G):\n        m, n = len(G), len(G[0])\n        ex_virus = []\n        spreading = []\n        walls = []\n        visited = [[False] * n for _ in range(m)]\n\n        for x in range(m):\n            for y in range(n):\n                if G[x][y] == self.VIRUS and not visited[x][y]:\n                    ex_virus.append(set())\n                    spreading.append(set())\n                    walls.append(0)\n                    self.dfs(x, y, G, visited, ex_virus, spreading, walls)\n\n        _max_save = _max_i = -1\n        s = len(spreading)\n        for i in range(s):\n            t = len(spreading[i])\n            if t > _max_save:\n                _max_save = t\n                _max_i = i\n\n        if _max_save == -1:\n            return 0\n\n        for i in range(s):\n            if i == _max_i:\n                for x, y in ex_virus[i]:\n                    G[x][y] = self.EX_VIRUS\n            else:\n                for x, y in spreading[i]:\n                    G[x][y] = self.VIRUS\n\n        return walls[_max_i]\n\n    def dfs(self, x, y, G, visited, ex_virus, spreading, walls):\n        m, n = len(G), len(G[0])\n        if not (0 <= x < m and 0 <= y < n) or visited[x][y]:\n            return\n\n        if G[x][y] == self.VIRUS:\n            visited[x][y] = True\n            ex_virus[-1].add((x, y))\n            for dx, dy in self.V:\n                _x = x + dx\n                _y = y + dy\n                self.dfs(_x, _y, G, visited, ex_virus, spreading, walls)\n        elif G[x][y] == self.NORMAL:\n            spreading[-1].add((x, y))\n            walls[-1] += 1\n"
  },
  {
    "path": "leetcode/750_number_of_corner_rectangles.py",
    "content": "class Solution:\n    def countCornerRectangles(self, G):\n        \"\"\"\n        :type G: List[List[int]]\n        :rtype: int\n\n        iterate every row and save all the pairs of 1 in current row\n        if there is some pair with same indices in passed row\n        and then we can ensure rectangles exist\n\n        note that:\n        1 pair:  0 rec\n        2 pairs: 0+1= 1 rec\n        4 pairs: 0+1+2+3= 6 recs\n        n pairs: C(n, 2) = n * (n - 1) / 2 = 0+1+2+...+(n-1)\n\n        example: 4 pairs => C(4, 2) = 6 recs\n        1   1\n        1   1\n        1   1\n        1   1\n        \"\"\"\n        ans = 0\n\n        if not G:\n            return ans\n\n        n = 0\n        count = {}\n        for R in G:\n            for end in range(1, len(R)):\n                if R[end] == 0:\n                    continue\n\n                for start in range(end):\n                    if R[start] == 0:\n                        continue\n\n                    if (start, end) not in count:\n                        count[start, end] = 0\n                        continue\n\n                    count[start, end] += 1\n\n                    ans += count[start, end]\n\n        return ans\n"
  },
  {
    "path": "leetcode/758_bold_words_in_string.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for s in (Solution(),):\n...     for _in, _out in (\n...         (([''], ''), ''),\n...         ((['abc', '123'], 'abcxyz123'), '<b>abc</b>xyz<b>123</b>'),\n...         ((['aaa','aab','bc'], 'aaabbcc'), '<b>aaabbc</b>c'),\n...         ((['ab', 'bc'], 'aabcd'), 'a<b>abc</b>d'),\n...     ):\n...         res = s.boldWords(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    def boldWords(self, words, s):\n        \"\"\"\n        :type words: List[str]\n        :type s: str\n        :rtype: str\n        \"\"\"\n        if not s or not words:\n            return ''\n\n        TMPL = '<b>{}</b>'\n        n = len(s)\n        ans = []\n        is_bold = [False] * n\n        left = right = 0\n\n        for left in range(n):\n            for w in words:\n                size = len(w)\n\n                if s[left:left + size] == w and left + size > right:\n                    right = left + size\n\n            is_bold[left] = right > left\n\n        left = right = 0\n\n        while left < n:\n            if not is_bold[left]:\n                ans.append(s[left])\n                left += 1\n                continue\n\n            right = left\n\n            while right < n and is_bold[right]:\n                right += 1\n\n            ans.append(TMPL.format(s[left:right]))\n            left = right  # imply left' = left + 1\n\n        return ''.join(ans)\n"
  },
  {
    "path": "leetcode/769_max_chunks_to_make_sorted.py",
    "content": "\"\"\"\nMain Concept:\ngiven nums: 0, 2, 1, 4, 3, 5, 7, 6\n\n1. the sorted nums is just its index\n2. maintain a `M` to record, and `M[i]` means the max in [0:i] in nums\n3. if `M[i] == i`, ans += 1\n\nsorted: 0, 1, 2, 3, 4, 5, 6, 7\nindex:  0, 1, 2, 3, 4, 5, 6, 7\nmax:    0, 2, 2, 4, 4, 5, 7, 7\nans:    1, 1, 2, 2, 3, 4, 4, 5\nchunks: 0| 2, 1| 4, 3| 5| 7, 6\n\n\nImprovement:\n\njust compare when visit it\nspace: O(n) -> O(1)\n\"\"\"\n\n\nclass Solution:\n    def maxChunksToSorted(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not nums:\n            return ans\n\n        _max = 0  # since 0 is the min in nums\n\n        for i in range(len(nums)):\n            _max = max(_max, nums[i])\n\n            if _max == i:\n                ans += 1\n\n        return ans\n\n\nclass Solution:\n    def maxChunksToSorted(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not nums:\n            return ans\n\n        n = len(nums)\n        M = [0] * n  # `M[i]` means the max in [0:i] in nums\n\n        for i in range(n):\n            M[i] = nums[i]\n\n            if i > 0 and M[i - 1] > M[i]:\n                M[i] = M[i - 1]\n\n        for i in range(n):\n            if M[i] == i:\n                ans += 1\n\n        return ans\n"
  },
  {
    "path": "leetcode/776_split_bst.py",
    "content": "# Definition for a binary tree node.\n# class TreeNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\n\nclass Solution:\n    def splitBST(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: int\n        :rtype: List[TreeNode]\n        \"\"\"\n        if not root:\n            return None, None\n\n        if root.val > target:\n            left, right = self.splitBST(root.left, target)\n            root.left = right\n            return left, root\n        else:\n            left, right = self.splitBST(root.right, target)\n            root.right = left\n            return root, right\n"
  },
  {
    "path": "leetcode/777_swap_adjacent_in_lr_string.py",
    "content": "class Solution:\n    def canTransform(self, start, end):\n        \"\"\"\n        :type start: str\n        :type end: str\n        :rtype: bool\n        \"\"\"\n        if len(start) != len(end):\n            return False\n\n        m, n = len(start), len(end)\n        i = j = 0\n\n        while i < m and j < n:\n            while i < m and start[i] == 'X':\n                i += 1\n            while j < n and end[j] == 'X':\n                j += 1\n\n            if i == m and j == n:\n                return True\n            if i == m or j == n:\n                return False\n\n            if start[i] != end[j]:\n                return False\n            if start[i] == 'L' and j > i:\n                return False\n            if start[i] == 'R' and i > j:\n                return False\n\n            i += 1\n            j += 1\n\n        return True\n"
  },
  {
    "path": "leetcode/778_swim_in_rising_water.py",
    "content": "from heapq import heappush, heappop\n\n\nclass Solution:\n    def swimInWater(self, G):\n        \"\"\"\n        :type G: List[List[int]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not G or not G[0]:\n            return ans\n\n        n = len(G)\n        V = ((-1, 0), (1, 0), (0, -1), (0, 1))\n\n        heap = [(G[0][0], 0, 0)]\n        visited = {(0, 0): True}\n\n        while heap:\n            depth, x, y = heappop(heap)\n            if depth > ans:\n                ans = depth\n            if x == y == n - 1:\n                return ans\n            for dx, dy in V:\n                _x = x + dx\n                _y = y + dy\n                if not (0 <= _x < n and 0 <= _y < n):\n                    continue\n                if (_x, _y) in visited:\n                    continue\n                visited[_x, _y] = True\n                heappush(heap, (G[_x][_y], _x, _y))\n\n        return ans\n"
  },
  {
    "path": "leetcode/779_k_th_symbol_in_grammar.py",
    "content": "class Solution:\n    def kthGrammar(self, N, K):\n        \"\"\"\n        :type N: int\n        :type K: int\n        :rtype: int\n        \"\"\"\n        if N == 1:\n            return 0\n\n        if K % 2 == 0:\n            if self.kthGrammar(N - 1, K // 2) == 0:\n                return 1\n            else:\n                return 0\n        else:\n            if self.kthGrammar(N - 1, (K + 1) // 2) == 0:\n                return 0\n            else:\n                return 1\n"
  },
  {
    "path": "leetcode/783_minimum_distance_between_bst_nodes.py",
    "content": "\"\"\"\nDefinition for a binary tree node.\nclass TreeNode:\n    def __init__(self, x):\n        self.val = x\n        self.left = None\n        self.right = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Recursion\n    time: O(n)\n    space: O(1)\n    \"\"\"\n    ans = float('inf')\n    pre = None\n\n    def minDiffInBST(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return self.ans\n\n        self.minDiffInBST(root.left)\n\n        if self.pre and root.val - self.pre.val < self.ans:\n            self.ans = root.val - self.pre.val\n\n        self.pre = root\n\n        self.minDiffInBST(root.right)\n        return self.ans\n\n\nclass Solution:\n    \"\"\"\n    Iteration\n    time: O(n)\n    space: O(n)\n    \"\"\"\n    def minDiffInBST(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return\n\n        ans = float('inf')\n        pre = None\n\n        stack = []\n        node = root\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n\n            if pre and node.val - pre.val < ans:\n                ans = node.val - pre.val\n\n            pre = node\n\n            node = node.right\n\n        return ans\n"
  },
  {
    "path": "leetcode/784_letter_case_permutation.py",
    "content": "class Solution:\n    def letterCasePermutation(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        if not s:\n            return ['']\n        ans = []\n        self.dfs(s, 0, ans, [])\n        return ans\n\n    def dfs(self, s, i, ans, path):\n        if i == len(s):\n            ans.append(''.join(path))\n            return\n\n        options = [s[i]] if s[i].isdigit() else [s[i].lower(), s[i].upper()]\n\n        for c in options:\n            path.append(c)\n            self.dfs(s, i + 1, ans, path)\n            path.pop()\n"
  },
  {
    "path": "leetcode/785_is_graph_bipartite.py",
    "content": "class Solution:\n    def isBipartite(self, graph):\n        \"\"\"\n        :type graph: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        color = {}\n\n        for node in range(len(graph)):\n            if node not in color:\n                color[node] = 0\n            for nei in graph[node]:\n                if nei not in color:\n                    color[nei] = color[node] ^ 1\n                elif color[nei] == color[node]:\n                    return False\n\n        return True\n"
  },
  {
    "path": "leetcode/786_k_th_smallest_prime_fraction.py",
    "content": "\"\"\"\nMain Concept:\njust like found kth smallest num in matrix\n\nexample: [1, 2, 5, 7]\n\n    7   5   2   1\n1  1/7 1/5 1/2 1/1\n2  2/7 2/5 ...\n5  ...\n7  ...\n\"\"\"\nfrom heapq import heappush, heappop\n\n\nclass Solution:\n    def kthSmallestPrimeFraction(self, A, K):\n        \"\"\"\n        :type A: List[int]\n        :type K: int\n        :rtype: List[int]\n        \"\"\"\n        heap = []\n        n = len(A)\n\n        A.sort()\n\n        for i in range(n):\n            heappush(heap, (A[i]/A[-1], i, n - 1))\n\n        for _ in range(K - 1):\n            _, i, j = heappop(heap)\n\n            j -= 1\n            if j >= 0:\n                heappush(heap, (A[i]/A[j], i, j))\n\n        _, i, j = heappop(heap)\n        return [A[i], A[j]]\n"
  },
  {
    "path": "leetcode/787_cheapest_flights_within_k_stops.py",
    "content": "class Solution:\n    def findCheapestPrice(self, n, flights, src, dst, K):\n        \"\"\"\n        :type n: int\n        :type flights: List[List[int]]\n        :type src: int\n        :type dst: int\n        :type K: int\n        :rtype: int\n        \"\"\"\n        min_cost = [float('inf')] * n  # the minimum cost to get to node\n        costs = [float('inf')] * n\n        min_cost[src] = costs[src] = 0\n\n        for _ in range(K + 1):\n            for u, v, cost in flights:\n                costs[v] = min(costs[v], min_cost[u] + cost)\n            min_cost = costs\n\n        return costs[dst] if costs[dst] < float('inf') else -1\n\n\nclass Solution:\n    def findCheapestPrice(self, n, flights, src, dst, K):\n        \"\"\"\n        :type n: int\n        :type flights: List[List[int]]\n        :type src: int\n        :type dst: int\n        :type K: int\n        :rtype: int\n        \"\"\"\n        if src == dst:\n            return 0\n\n        INF = float('inf')\n\n        \"\"\"\n        `dp[i][k]` means the cost when the end is `i` with `k` stop\n        \"\"\"\n        dp = [[INF] * (K + 1) for _ in range(n)]\n        dp[src][0] = 0\n\n        for start, end, cost in flights:\n            if start == src and cost < dp[end][0]:\n                dp[end][0] = cost\n\n        for k in range(1, K + 1):\n            for i in range(n):\n                dp[i][k] = dp[i][k - 1]\n\n            for start, end, cost in flights:\n                dp[end][k] = min(\n                    dp[end][k],\n                    dp[start][k - 1] + cost\n                )\n\n        return dp[dst][K] if dp[dst][K] < INF else -1\n"
  },
  {
    "path": "leetcode/788_rotated_digits.py",
    "content": "class Solution:\n    def rotatedDigits(self, N):\n        \"\"\"\n        :type N: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        for i in range(1, N + 1):\n            if self.is_good(i):\n                ans += 1\n\n        return ans\n\n    def is_good(self, N):\n        res = False\n\n        while N > 0:\n            D = N % 10\n            if D in (3, 4, 7):\n                return False\n            if D in (2, 5, 6, 9):\n                res = True\n            N = N // 10\n\n        return res\n"
  },
  {
    "path": "leetcode/789_escape_the_ghosts.py",
    "content": "class Solution:\n    def escapeGhosts(self, ghosts, target):\n        \"\"\"\n        :type ghosts: List[List[int]]\n        :type target: List[int]\n        :rtype: bool\n        \"\"\"\n        R, C = target\n        pacman_dist = abs(R) + abs(C)  # (R - 0) + (C - 0)\n\n        for x, y in ghosts:\n            ghost_dist = abs(R - x) + abs(C - y)\n            if ghost_dist <= pacman_dist:\n                return False\n\n        return True\n"
  },
  {
    "path": "leetcode/790_domino_and_tromino_tiling.py",
    "content": "class Solution:\n    def numTilings(self, N):\n        \"\"\"\n        :type N: int\n        :rtype: int\n        \"\"\"\n        if N < 3:\n            return N\n\n        MOD = 10 ** 9 + 7\n        dp = [0] * (N + 1)\n        dp[:3] = 1, 1, 2\n\n        for i in range(3, N + 1):\n            dp[i] = (dp[i - 1] * 2 + dp[i - 3]) % MOD\n\n        return dp[N]\n"
  },
  {
    "path": "leetcode/791_custom_sort_string.py",
    "content": "class Solution:\n    def customSortString(self, S, T):\n        \"\"\"\n        :type S: str\n        :type T: str\n        :rtype: str\n        \"\"\"\n        return ''.join(sorted(T, key=lambda c: S.find(c)))\n"
  },
  {
    "path": "leetcode/7_reverse_integer.py",
    "content": "class Solution:\n    def reverse(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not x:\n            return ans\n\n        INT_MAX = 0x7FFFFFFF\n        _x = x if x > 0 else -x\n\n        while _x:\n            ans = ans * 10 + _x % 10\n            _x //= 10\n\n        if ans >= INT_MAX:\n            return 0\n\n        return ans if x > 0 else -ans\n"
  },
  {
    "path": "leetcode/81_search_in_rotated_sorted_array_ii.py",
    "content": "class Solution:\n    def search(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return False\n\n        for num in nums:\n            if num == target:\n                return True\n\n        return False\n"
  },
  {
    "path": "leetcode/8_string_to_integer_atoi.py",
    "content": "class Solution:\n    def myAtoi(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not s:\n            return ans\n\n        INT_MAX = 0x7FFFFFFF\n        N = len(s)\n        ZERO = ord('0')\n\n        sign = 1\n        i = 0\n\n        while i < N and s[i] == ' ':\n            i += 1\n\n        if i < N and s[i] in ('+', '-'):\n            sign = -1 if s[i] == '-' else 1\n            i += 1\n\n        while i < N and s[i].isdigit():\n            val = ord(s[i]) - ZERO\n\n            if (ans > INT_MAX // 10 or\n                (ans == INT_MAX // 10 and val > 7)):\n                return INT_MAX if sign == 1 else ~INT_MAX\n\n            ans = ans * 10 + val\n            i += 1\n\n        return sign * ans\n"
  },
  {
    "path": "lintcode/102_linked_list_cycle.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: The first node of linked list.\n    @return: True if it has a cycle, or false\n    \"\"\"\n    def hasCycle(self, head):\n        \"\"\"\n        if its a cycle, and then we can ensure\n        the 2-pace pointer and the 1-pace pointer\n        will eventually meet\n        otherwise its a list => at some point there will be no `node.next`\n        \"\"\"\n        if not head or not head.next:\n            return False\n\n        slow = head\n        fast = head.next\n        while slow != fast:\n            if not fast.next or not fast.next.next:\n                return False\n\n            slow = slow.next\n            fast = fast.next.next\n\n        return True\n"
  },
  {
    "path": "lintcode/103_linked_list_cycle_ii.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: The first node of linked list.\n    @return: The node where the cycle begins. if there is no cycle, return null\n    \"\"\"\n    def detectCycle(self, head):\n        \"\"\"\n        example: 1->2->3\n                    ^  v\n                    5<-4\n\n        * h: head, s: slow, f: fast, i: intersection node\n\n        r1/\n            s    f\n            1 -> 2 -> 3\n                 ^    v\n                 5 <- 4\n\n        r2/\n                 s\n            1 -> 2 -> 3\n                 ^    v\n                 5 <- 4  f\n\n        r3/\n                 f    s\n            1 -> 2 -> 3\n                 ^    v\n                 5 <- 4\n\n        r4/\n            h    i\n            1 -> 2 -> 3\n                 ^    v\n                 5 <- 4  s, f\n\n        h->i == 1\n        s->i == 2\n        \"\"\"\n        if not head or not head.next:\n            return\n\n        \"\"\"\n        if its a cycle, and then we can ensure\n        the 2-pace pointer and the 1-pace pointer\n        will eventually meet\n        otherwise its a list => at some point there will be no `node.next`\n        \"\"\"\n        slow, fast = head, head.next\n        while slow is not fast:\n            if not fast or not fast.next:\n                return\n            slow = slow.next\n            fast = fast.next.next\n\n        \"\"\"\n        at this point, slow meet fast\n        and at the intersection node\n        the steps from the first node is equal to from meet node plus 1\n        \"\"\"\n        while head is not slow.next:\n            head = head.next\n            slow = slow.next\n\n        return head\n"
  },
  {
    "path": "lintcode/104_merge_k_sorted_lists.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\nimport heapq\n\n\nclass Solution:\n    def mergeKLists(self, lists):\n        \"\"\"\n        :type lists: list[ListNode]\n        :rtype: ListNode\n        \"\"\"\n        if not lists:\n            return\n\n        dummy = tail = ListNode(-1)\n        heap = []\n\n        for i in range(len(lists)):\n            if not lists[i]:\n                continue\n\n            heapq.heappush(heap, (lists[i].val, i))\n\n        while heap:\n            val, i = heapq.heappop(heap)\n\n            tail.next = ListNode(val)\n            tail = tail.next\n\n            if lists[i].next:\n                lists[i] = lists[i].next\n                heapq.heappush(heap, (lists[i].val, i))\n\n        return dummy.next\n"
  },
  {
    "path": "lintcode/105_copy_list_with_random_pointer.py",
    "content": "\"\"\"\nDefinition for singly-linked list with a random pointer.\nclass RandomListNode:\n    def __init__(self, x):\n        self.label = x\n        self.next = None\n        self.random = None\n\"\"\"\n\n\n\"\"\"\nusing hashmap\ntime: O(2n) => O(n)\nspace: O(n)\n\"\"\"\nclass Solution:\n    def copyRandomList(self, head):\n        \"\"\"\n        :type head: RandomListNode\n        :rtype: RandomListNode\n        \"\"\"\n        N = {}\n        dummy = tail = RandomListNode(-1)\n\n        while head:\n            node = RandomListNode(head.label)\n            node.random = head.random\n            tail.next = node\n            N[head] = node\n            tail = tail.next\n            head = head.next\n\n        head = dummy.next\n        while head:\n            if head.random:\n                head.random = N[head.random]\n            head = head.next\n\n        return dummy.next\n\n\n\"\"\"\ntemply save in n.next\ntime: O(3n) => O(n)\nspace: O(1)\n\n\nexample: 1->2->3\n\ncopy_next/\n    |--------->|\n    1 -> 1' -> 2 -> 2' -> 3 -> 3'\nreplace_random/\n         |--------->|\n    |----+---->|    |\n    1 -> 1' -> 2 -> 2' -> 3 -> 3'\nsplit_list/\n    |--------->|\n    1    ->    2    ->    3\n         1'   ->    2'   ->    3'\n         |--------->|\n\"\"\"\nclass Solution:\n    def copyRandomList(self, head):\n        \"\"\"\n        :type head: RandomListNode\n        :rtype: RandomListNode\n        \"\"\"\n        if not head:\n            return\n\n        tail = head\n        node = None\n        while tail:\n            node = RandomListNode(tail.label)\n            node.random = tail.random\n            node.next = tail.next\n            tail.next = node\n            tail = tail.next.next\n\n        tail = head\n        while tail:\n            if tail.next and tail.random:\n                tail.next.random = tail.random.next\n            tail = tail.next.next\n\n        node = tail = head.next\n        while tail and tail.next:\n            tail.next = tail.next.next\n            tail = tail.next\n\n        return node\n"
  },
  {
    "path": "lintcode/107_word_break.py",
    "content": "class Solution:\n    \"\"\"\n    `dp[i]` means `s[:i]` is segmented by words\n    \"\"\"\n    def wordBreak(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: List[str]\n        :rtype: bool\n        \"\"\"\n        if not s and not words:\n            return True\n        if not s or not words:\n            return False\n\n        max_size = max(len(w) for w in words)\n        word_set = set(words)\n\n        n = len(s)\n        dp = [False] * (n + 1)\n        dp[0] = True\n\n        for i in range(1, n + 1):\n            for j in range(1, min(i, max_size) + 1):\n                if dp[i - j] and s[i - j:i] in word_set:\n                    dp[i] = True\n                    break\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/108_palindrome_partitioning_ii.py",
    "content": "class Solution:\n    # @param S, a string\n    # @return an integer\n    def minCut(self, S):\n        if not S:\n            return -1\n\n        n = len(S)\n        INFINITY = float('inf')\n        is_palindrome = self.get_palin_map(S)\n\n        \"\"\"\n        `dp[i]` means the minimum palindrome count\n        broken from the substring ended at `i`\n        \"\"\"\n        dp = [INFINITY] * (n + 1)\n        dp[0] = 0\n\n        for end in range(1, n + 1):\n            for start in range(end):\n                if (not is_palindrome[start][end - 1] or\n                    dp[start] is INFINITY):\n                    continue\n                if dp[start] + 1 < dp[end]:\n                    dp[end] = dp[start] + 1\n\n        return dp[n] - 1\n\n    def get_palin_map(self, S):\n        n = len(S)\n        is_palindrome = [[False] * n for _ in range(n)]\n        is_palindrome[0][0] = True\n\n        for end in range(1, n):\n            is_palindrome[end][end] = True\n\n            start = end - 1\n            is_palindrome[start][end] = (S[start] == S[end])\n\n        for start in range(n - 1 - 2, -1, -1):\n            for end in range(start + 2, n):\n                if not is_palindrome[start + 1][end - 1]:\n                    continue\n                is_palindrome[start][end] = (S[start] == S[end])\n\n        return is_palindrome\n"
  },
  {
    "path": "lintcode/109_triangle.py",
    "content": "\"\"\"\nDP: Memory Searching\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: triangle: a list of lists of integers\n    @return: An integer, minimum path sum\n    \"\"\"\n    def minimumTotal(self, triangle):\n        if not triangle or not triangle[0]:\n            return 0\n\n        return self.memo_search(0, 0, triangle, {})\n\n    def memo_search(self, depth, start, triangle, memo):\n        if depth == len(triangle) - 1:\n            return triangle[depth][start]\n\n        key = (depth, start)\n\n        if key in memo:\n            return memo[key]\n\n        memo[key] = min(\n            self.memo_search(depth + 1, start, triangle, memo),\n            self.memo_search(depth + 1, start + 1, triangle, memo)\n        )\n\n        memo[key] += triangle[depth][start]\n\n        return memo[key]\n\n\n\"\"\"\nDP: Top-down Recuring + Rolling Array\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: triangle: a list of lists of integers\n    @return: An integer, minimum path sum\n    \"\"\"\n    def minimumTotal(self, triangle):\n        if not triangle or not triangle[0]:\n            return 0\n\n        INFINITY = float('inf')\n        m = len(triangle)\n        dp = [[INFINITY] * (m + 1) for _ in range(2)]\n\n        prev = curr = 0\n        for i in range(1, m + 1):\n            prev = curr\n            curr = 1 - curr\n\n            for j in range(1, i + 1):\n                \"\"\"\n                dp[prev][j] == dp[i - 1][j]\n                dp[curr][j] == dp[i][j]\n                \"\"\"\n\n                dp[curr][j] = triangle[i - 1][j - 1]\n\n                if dp[prev][j - 1] < INFINITY or dp[prev][j] < INFINITY:\n                    \"\"\"\n                    NO need to calculate first,\n                    since only one path from top\n                    \"\"\"\n                    dp[curr][j] += min(\n                        dp[prev][j - 1],\n                        dp[prev][j]\n                    )\n\n        return min(dp[curr])\n\n\n\"\"\"\nDP: Bottom-up Recuring + Rolling Array\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: triangle: a list of lists of integers\n    @return: An integer, minimum path sum\n    \"\"\"\n    def minimumTotal(self, triangle):\n        if not triangle or not triangle[0]:\n            return 0\n\n        INFINITY = float('inf')\n        m = len(triangle)\n        dp = [[INFINITY] * (m + 1) for _ in range(m + 1)]\n\n        prev = curr = 0\n        for i in range(m - 1, -1, -1):\n            prev = curr\n            curr = 1 - curr\n\n            for j in range(i + 1):\n                \"\"\"\n                dp[prev][j] == dp[i + 1][j]\n                dp[curr][j] == dp[i][j]\n                \"\"\"\n\n                dp[curr][j] = triangle[i][j]\n\n                if dp[prev][j] < INFINITY or dp[prev][j + 1] < INFINITY:\n                    \"\"\"\n                    MUST be calculated first,\n                    since there are two paths from bottom\n                    and `dp[curr][j]` maybe negative\n                    \"\"\"\n                    dp[curr][j] = min(\n                        dp[curr][j] + dp[prev][j],\n                        dp[curr][j] + dp[prev][j + 1]\n                    )\n\n        return dp[curr][0]\n"
  },
  {
    "path": "lintcode/10_string_permutation_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: S: A string\n    @return: all permutations\n    \"\"\"\n    def stringPermutation2(self, S):\n        if not S:\n            return ['']\n\n        S = sorted(S)\n\n        ans = []\n        self.dfs(S, ans, [])\n        return ans\n\n    def dfs(self, S, ans, path):\n        if not S:\n            ans.append(''.join(path))\n            return\n\n        for i in range(len(S)):\n            if i > 0 and S[i] == S[i - 1]:\n                continue\n            path.append(S[i])\n            self.dfs(S[:i] + S[i + 1:], ans, path)\n            path.pop()\n"
  },
  {
    "path": "lintcode/110_minimum_path_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: grid: a list of lists of integers\n    @return: An integer, minimizes the sum of all numbers along its path\n    \"\"\"\n    def minPathSum(self, grid):\n        if not grid:\n            return 0\n\n        m, n = len(grid), len(grid[0])\n\n        dp = [[0] * n for _ in range(m)]\n\n        for j in range(n):\n            if j == 0:\n                dp[0][j] = grid[0][j]\n                continue\n\n            dp[0][j] = grid[0][j] + dp[0][j - 1]\n\n        for i in range(1, m):\n            dp[i][0] = grid[i][0] + dp[i - 1][0]\n\n            for j in range(1, n):\n                if dp[i - 1][j] < dp[i][j - 1]:\n                    dp[i][j] = grid[i][j] + dp[i - 1][j]\n                else:\n                    dp[i][j] = grid[i][j] + dp[i][j - 1]\n\n        return dp[m - 1][n - 1]\n"
  },
  {
    "path": "lintcode/111_climbing_stairs.py",
    "content": "\"\"\"\nDP: rolling array with `n + 1`\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param n: An integer\n    @return: An integer\n    \"\"\"\n    def climbStairs(self, n):\n        if n <= 0:\n            return 0\n\n        dp = [0] * 3\n\n        pre2, pre1, curr = 0, 0, 1\n        dp[0] = dp[1] = 1\n\n        for i in range(2, n + 1):\n            pre2 = pre1\n            pre1 = curr\n            curr = i % 3\n\n            dp[curr] = dp[pre1] + dp[pre2]\n\n        return dp[curr]\n\n\n\"\"\"\nDP: origin `n`\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param n: An integer\n    @return: An integer\n    \"\"\"\n    def climbStairs(self, n):\n        if n <= 0:\n            return 0\n\n        dp = [0] * n\n\n        dp[0] = 1\n        dp[1] = 2\n\n        for i in range(2, n):\n            dp[i] = dp[i - 1] + dp[i - 2]\n\n        return dp[n - 1]\n\n\n\"\"\"\nDP: origin `n + 1`\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param n: An integer\n    @return: An integer\n    \"\"\"\n    def climbStairs(self, n):\n        if n <= 0:\n            return 0\n\n        dp = [0] * (n + 1)\n\n        dp[0] = dp[1] = 1\n\n        for i in range(2, n + 1):\n            dp[i] = dp[i - 1] + dp[i - 2]\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/114_unique_paths.py",
    "content": "class Solution:\n    def uniquePaths(self, m, n):\n        \"\"\"\n        :type m: int\n        :type n: int\n        :rtype: int\n        \"\"\"\n        dp = [[1] * n for _ in range(m)]\n\n        for x in range(1, m):\n            for y in range(1, n):\n                dp[x][y] = dp[x - 1][y] + dp[x][y - 1]\n\n        return dp[m - 1][n - 1]\n"
  },
  {
    "path": "lintcode/115_unique_paths_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: G: A list of lists of integers\n    @return: An integer\n    \"\"\"\n    def uniquePathsWithObstacles(self, G):\n        if not G or not G[0]:\n            return 0\n\n        OBSTACLE = 1\n\n        m, n = len(G), len(G[0])\n        dp = [[0] * n for _ in range(2)]\n        prev = curr = 0\n\n        for j in range(n):\n            if G[0][j] == OBSTACLE:\n                break\n            dp[curr][j] = 1\n\n        for i in range(1, m):\n            prev = curr\n            curr = 1 - curr\n\n            dp[curr][0] = 0 if G[i][0] == OBSTACLE else dp[prev][0]\n            for j in range(1, n):\n                if G[i][j] == OBSTACLE:\n                    dp[curr][j] = 0\n                    continue\n                dp[curr][j] = dp[prev][j] + dp[curr][j - 1]\n\n        return dp[curr][n - 1]\n"
  },
  {
    "path": "lintcode/116_jump_game.py",
    "content": "\"\"\"\nGreedy\n\nhttps://leetcode.com/articles/jump-game/\n\"\"\"\nclass Solution:\n    def canJump(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: bool\n        \"\"\"\n        if not A:\n            return False\n\n        last_at = len(A) - 1\n\n        for i in range(last_at, -1, -1):\n            if i + A[i] >= last_at:\n                last_at = i\n\n        return last_at == 0\n\n\n\"\"\"\nDP\n\"\"\"\nclass Solution:\n    def canJump(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: bool\n        \"\"\"\n        if not A:\n            return False\n\n        n = len(A)\n        dp = [False] * n\n\n        \"\"\"\n        `dp[i]` means `i` could be reached\n        \"\"\"\n        dp[0] = True\n\n        for i in range(1, n):\n            for j in range(i):\n                \"\"\"\n                backtracking\n                if `j` could be reached\n                \"\"\"\n                if dp[j] and j + A[j] >= i:\n                    \"\"\"\n                    if jump from `j` can reach `i`\n                    \"\"\"\n                    dp[i] = True\n                    break\n\n        return dp[n - 1]\n"
  },
  {
    "path": "lintcode/117_jump_game_ii.py",
    "content": "\"\"\"\nGreedy\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @return: An integer\n    \"\"\"\n    def jump(self, A):\n        if not A:\n            return -1\n\n        target = len(A) - 1\n        start = end = jumps = 0\n\n        while end < target:\n            jumps += 1\n            furthest = end\n            for i in range(start, end + 1):\n                if i + A[i] > furthest:\n                    furthest = i + A[i]\n            start = end + 1\n            end = furthest\n\n        return jumps\n\n\n\"\"\"\nDP\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @return: An integer\n    \"\"\"\n    def jump(self, A):\n        if not A:\n            return -1\n\n        INFINITY = float('inf')\n\n        n = len(A)\n        dp = [INFINITY] * n\n        dp[0] = 0\n\n        for i in range(1, n):\n            for j in range(i):\n                if (dp[j] < INFINITY and j + A[j] >= i and\n                    dp[j] + 1 < dp[i]):\n                    dp[i] = dp[j] + 1\n\n        return dp[n - 1]\n"
  },
  {
    "path": "lintcode/118_distinct_subsequences.py",
    "content": "class Solution:\n    \"\"\"\n    @param: : A string\n    @param: : A string\n    @return: Count the number of distinct subsequences\n    \"\"\"\n    def numDistinct(self, S, T):\n        if S is None or T is None:\n            return 0\n\n        if S is '' and '':\n            return 1\n\n        m, n = len(S), len(T)\n\n        \"\"\"\n        `dp[i][j]` means the count of distinct subsequences\n        (the substr end at `T[j - 1]`) in the substr end at `S[i - 1]`\n        \"\"\"\n        dp = [[0] * (n + 1) for _ in range(2)]\n\n        prev = curr = 0\n        dp[curr][0] = 1\n        for i in range(1, m + 1):\n            prev = curr\n            curr = 1 - curr\n\n            dp[curr][0] = 1\n\n            for j in range(1, n + 1):\n                \"\"\"\n                case 1: `S[i - 1]` and `T[j - 1]` is not a pair\n                so keep `T[j - 1]` in candidates\n                \"\"\"\n                dp[curr][j] = dp[prev][j]\n\n                \"\"\"\n                case 2: `S[i - 1]` and `T[j - 1]` is a pair\n                do NOT `+1` -> its for size, this problem is for count\n                \"\"\"\n                if S[i - 1] == T[j - 1]:\n                    dp[curr][j] += dp[prev][j - 1]\n\n        return dp[curr][n]\n"
  },
  {
    "path": "lintcode/119_edit_distance.py",
    "content": "class Solution:\n    def minDistance(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: int\n        \"\"\"\n        if s is None or t is None:\n            return 0\n\n        m, n = len(s), len(t)\n\n        \"\"\"\n        `dp[i][j]` means the minimum operations to convert\n        the substr end at `A[i - 1]` to\n        the substr end at `B[j - 1]`\n        \"\"\"\n        dp = [[0] * (n + 1) for _ in range(m + 1)]\n\n        for i in range(1, m + 1):\n            dp[i][0] = i\n        for j in range(1, n + 1):\n            dp[0][j] = j\n\n        for i in range(1, m + 1):\n            for j in range(1, n + 1):\n                \"\"\"\n                no need to init dp[curr][j]\n\n                case 1: no need to do any operations\n                \"\"\"\n                if s[i - 1] == t[j - 1]:\n                    dp[i][j] = dp[i - 1][j - 1]\n                    continue\n\n                \"\"\"\n                case 2: remove last char in A\n                case 3: add `B[j - 1]` to the end of A\n                case 4: replace laster char in A\n                \"\"\"\n                dp[i][j] = 1 + min(\n                    dp[i - 1][j],\n                    dp[i][j - 1],\n                    dp[i - 1][j - 1]\n                )\n\n        return dp[m][n]\n"
  },
  {
    "path": "lintcode/11_search_range_in_binary_search_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def searchRange(self, root, a, b):\n        \"\"\"\n        :type root: TreeNode\n        :type a: int\n        :type b: int\n        :rtype: list[int]\n        \"\"\"\n        ans = []\n\n        if not root:\n            return ans\n\n        self.dfs(root, a, b, ans)\n\n        return ans\n\n    def dfs(self, node, a, b, ans):\n        if not node:\n            return\n\n        self.dfs(node.left, a, b, ans)\n\n        if a <= node.val <= b:\n            ans.append(node.val)\n\n        self.dfs(node.right, a, b, ans)\n"
  },
  {
    "path": "lintcode/120_word_ladder.py",
    "content": "\"\"\"\nTest Case:\n\n\"a\"\n\"a\"\n[\"b\"]\n=> should check again words in queue\n\"\"\"\n\n\nclass Solution:\n    def ladderLength(self, s, e, D):\n        \"\"\"\n        :type s: str\n        :type e: str\n        :type D: List[str]\n        :rtype: int\n        \"\"\"\n        if (not s or not e or\n            len(s) != len(e) or not D):\n            return 0\n        if s == e:\n            return 1\n\n        if s not in D:\n            D.append(s)\n        if e not in D:\n            D.append(e)\n\n        n = len(s)\n        next_words = [None] * n\n        for i in range(n):\n            next_words[i] = _words = {}\n            for word in D:\n                key = word[:i] + word[i + 1:]\n                if key not in _words:\n                    _words[key] = set()\n                _words[key].add(word)\n\n        queue = [e]\n        distance = {e: 1}\n        for word in queue:\n            for _word in self.get_next_word(word, next_words):\n                if _word in distance:\n                    continue\n                distance[_word] = distance[word] + 1\n                if _word == s:\n                    return distance[_word]\n                queue.append(_word)\n\n        return 0\n\n    def get_next_word(self, word, next_words):\n        for i in range(len(word)):\n            key = word[:i] + word[i + 1:]\n            if key not in next_words[i]:\n                continue\n            for _word in next_words[i][key]:\n                if _word == word:\n                    continue\n                yield _word\n"
  },
  {
    "path": "lintcode/121_word_ladder_ii.py",
    "content": "\"\"\"\nMain Concept:\n\n1. building `next_words` in advance to speed up\n2. using BFS from `B` to `A` to calculate the distance guide\n3. using DFS step by step to find all possible path to get `B`\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: a string\n    @param: B: a string\n    @param: D: a set of string\n    @return: a list of lists of string\n    \"\"\"\n    def findLadders(self, A, B, D):\n        ans = []\n        if (D is None or A is None or B is None or\n            len(A) != len(B)):\n            return ans\n\n        if A not in D:\n            D.add(A)\n        if B not in D:\n            D.add(B)\n\n        n = len(A)\n        next_words = [None] * n\n        for i in range(n):\n            next_words[i] = W = {}\n            for word in D:\n                key = word[:i] + word[i + 1:]\n                if key not in W:\n                    W[key] = set()\n                W[key].add(word)\n\n        queue = [B]\n        distance = {B: 1}\n        for word in queue:\n            if word == A:\n                break\n            for _word in self.get_next_word(word, next_words):\n                if _word in distance:\n                    continue\n                distance[_word] = distance[word] + 1\n                queue.append(_word)\n\n        self.dfs(A, B, next_words, distance, ans, [A])\n        return ans\n\n    def dfs(self, word, B, next_words, distance, ans, path):\n        if word == B:\n            ans.append(path[:])\n            return\n\n        for _word in self.get_next_word(word, next_words):\n            if (_word not in distance or\n                distance[_word] != distance[word] - 1):\n                continue\n            path.append(_word)\n            self.dfs(_word, B, next_words, distance, ans, path)\n            path.pop()\n\n    def get_next_word(self, word, next_words):\n        for i in range(len(word)):\n            key = word[:i] + word[i + 1:]\n            if key not in next_words[i]:\n                continue\n            for _word in next_words[i][key]:\n                if _word == word:\n                    continue\n                yield _word\n"
  },
  {
    "path": "lintcode/122_largest_rectangle_in_histogram.py",
    "content": "\"\"\"\nREF: https://aaronice.gitbooks.io/lintcode/content/data_structure/largest_rectangle_in_histogram.html\n\"\"\"\n\n\n\"\"\"\nBrute Force: TLE\n\"\"\"\nclass Solution:\n    def largestRectangleArea(self, H):\n        \"\"\"\n        :type H: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not H:\n            return ans\n\n        n = len(H)\n        L = [0] * n  # lowest height\n\n        for left in range(n):\n            for right in range(left, n):\n                L[right] = H[right]\n\n                if right > left and L[right - 1] < H[right]:\n                    L[right] = L[right - 1]\n\n                area = L[right] * (right - left + 1)\n                if area > ans:\n                    ans = area\n\n        return ans\n\n\n\"\"\"\nBrute Force with Pruning\n\"\"\"\nclass Solution:\n    def largestRectangleArea(self, H):\n        \"\"\"\n        :type H: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not H:\n            return ans\n\n        n = len(H)\n\n        for right in range(len(H)):\n            if right < n - 1 and H[right] <= H[right + 1]:\n                continue\n            Hmin = H[right]\n            for left in range(right, -1, -1):\n                if H[left] < Hmin:\n                    Hmin = H[left]\n\n                area = Hmin * (right - left + 1)\n                if area > ans:\n                    ans = area\n\n        return ans\n\n\n\"\"\"\nMono-stack\n\"\"\"\nclass Solution:\n    def largestRectangleArea(self, H):\n        \"\"\"\n        :type H: List[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not H:\n            return ans\n\n        H.append(0)\n        stack = []\n\n        for right in range(len(H)):\n            while stack and H[stack[-1]] >= H[right]:\n                height = H[stack.pop()]\n                left = stack[-1] if stack else -1\n                area = height * (right - left - 1)\n                if area > ans:\n                    ans = area\n            stack.append(right)\n\n        return ans\n"
  },
  {
    "path": "lintcode/123_word_search.py",
    "content": "class Solution:\n    V = (\n        (-1,  0),\n        ( 1,  0),\n        ( 0, -1),\n        ( 0,  1),\n    )\n\n    \"\"\"\n    @param: G: A list of lists of character\n    @param: s: A string\n    @return: A boolean\n    \"\"\"\n    def exist(self, G, s):\n        if G is None or G[0] is None or s is None:\n            return False\n\n        m, n = len(G), len(G[0])\n        visited = [[False] * n for _ in range(m)]\n        for x in range(m):\n            for y in range(n):\n                if (G[x][y] == s[0] and\n                    self.dfs(G, x, y, s, 1, visited)):\n                    return True\n\n        return False\n\n    def dfs(self, G, x, y, s, i, visited):\n        if i >= len(s):\n            return True\n\n        for dx, dy in self.V:\n            _x = x + dx\n            _y = y + dy\n            if not (0 <= _x < len(G) and 0 <= _y < len(G[0])):\n                continue\n            if visited[_x][_y] or G[_x][_y] != s[i]:\n                continue\n\n            visited[_x][_y] = True\n            if self.dfs(G, _x, _y, s, i + 1, visited):\n                return True\n            visited[_x][_y] = False\n\n        return False\n"
  },
  {
    "path": "lintcode/124_longest_consecutive_sequence.py",
    "content": "class Solution:\n    \"\"\"\n    maintain a set to record if there is unused cands\n    \"\"\"\n    def longestConsecutive(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not nums:\n            return ans\n\n        cands = set(nums)  # dedup\n\n        for a in nums:\n            if a not in cands:\n                continue\n\n            cands.discard(a)\n            size = 1\n            b, c = a - 1, a + 1\n\n            while b in cands:\n                cands.discard(b)\n                b -= 1\n                size += 1\n\n            while c in cands:\n                cands.discard(c)\n                c += 1\n                size += 1\n\n            if size > ans:\n                ans = size\n\n        return ans\n\n\nclass Solution:\n    \"\"\"\n    1. sorted\n    2. if its consecutive, add 1 for size\n    3. save the maximum size\n    \"\"\"\n    def longestConsecutive(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not nums:\n            return ans\n\n        nums.sort()\n\n        size = 1\n\n        for i in range(1, len(nums)):\n            if nums[i] == nums[i - 1]:\n                continue\n\n            if nums[i] == nums[i - 1] + 1:\n                size += 1\n            else:\n                size = 1\n\n            if size > ans:\n                ans = size\n\n        return ans if ans > 0 else size\n"
  },
  {
    "path": "lintcode/125_backpack_ii.py",
    "content": "\"\"\"\nRolling Array\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: m: An integer m denotes the size of a backpack\n    @param: A: Given n items with size A[i]\n    @param: V: Given n items with value V[i]\n    @return: The maximum value\n    \"\"\"\n    def backPackII(self, m, A, V):\n        if not m or not A or not V:\n            return 0\n\n        # `dp[i][w]` means the maximum value\n        # with weight `w` in the former `i` items\n        dp = [[0] * (m + 1) for _ in range(2)]\n\n        prev = curr = 0\n        for i in range(1, len(A) + 1):\n            prev = curr\n            curr = 1 - curr\n            for w in range(1, m + 1):\n                dp[curr][w] = dp[prev][w]\n\n                if w >= A[i - 1]:\n                    dp[curr][w] = max(\n                        dp[curr][w],\n                        dp[prev][w - A[i - 1]] + V[i - 1]\n                    )\n\n        return dp[curr][m]\n\n\n\"\"\"\nOrigin\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: m: An integer m denotes the size of a backpack\n    @param: A: Given n items with size A[i]\n    @param: V: Given n items with value V[i]\n    @return: The maximum value\n    \"\"\"\n    def backPackII(self, m, A, V):\n        if not m or not A or not V:\n            return 0\n\n        n = len(A)\n        dp = [[0] * (m + 1) for _ in range(n + 1)]\n\n        for i in range(1, n + 1):\n            for w in range(1, m + 1):\n                dp[i][w] = dp[i - 1][w]\n\n                if w >= A[i - 1]:\n                    dp[i][w] = max(\n                        dp[i][w],\n                        dp[i - 1][w - A[i - 1]] + V[i - 1]\n                    )\n\n        return dp[n][m]\n"
  },
  {
    "path": "lintcode/126_max_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: Given an integer array with no duplicates.\n    @return: The root of max tree.\n    \"\"\"\n    \"\"\"\n    Assuming A = [2,5,6,0,3,1]\n    step1/ val: 2, stack: [2]\n    step2/ val: 5, stack: [5{2,}]\n    step3/ val: 6, stack: [6{5{2,},}]\n    step4/ val: 0, stack: [6{5{2,},0}, 0]\n    step5/ val: 3, stack: [6{5{2,},3{0,}}, 3{0,}]\n    step6/ val: 1, stack: [6{5{2,},3{0,1}}, 3{0,1}, 1]\n    \"\"\"\n    def maxTree(self, A):\n        stack = []\n        for val in A:\n            node = TreeNode(val)\n            while stack and val > stack[-1].val:\n                node.left = stack.pop()\n\n            # current val less than the last node in stack\n            if stack:\n                stack[-1].right = node\n\n            stack.append(node)\n        return stack[0]\n"
  },
  {
    "path": "lintcode/127_topological_sorting.py",
    "content": "\"\"\"\nDefinition for a Directed graph node\nclass DirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: graph: A list of Directed graph node\n    @return: Any topological order for the given graph.\n    \"\"\"\n    def topSort(self, graph):\n        ans = []\n        if not graph:\n            return ans\n\n        indegs = {}\n        for node in graph:\n            if node not in indegs:\n                indegs[node] = 0\n            for _node in node.neighbors:\n                if _node not in indegs:\n                    indegs[_node] = 0\n                indegs[_node] += 1\n\n        queue = [node for node, indeg in indegs.items() if indeg == 0]\n        for node in queue:\n            ans.append(node)\n            for _node in node.neighbors:\n                indegs[_node] -= 1\n                if indegs[_node] == 0:\n                    queue.append(_node)\n\n        return ans\n"
  },
  {
    "path": "lintcode/128_hash_function.py",
    "content": "class Solution:\n    \"\"\"\n    @param: key: A string you should hash\n    @param: HASH_SIZE: An integer\n    @return: An integer\n    \"\"\"\n    def hashCode(self, key, HASH_SIZE):\n        if not key:\n            return 0\n\n        MAGIC_NUMBER = 33\n\n        _code = 0\n        for char in key:\n            _code = (_code * MAGIC_NUMBER + ord(char)) % HASH_SIZE\n\n        return _code\n"
  },
  {
    "path": "lintcode/129_rehashing.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param hash_table: A list of The first node of linked list\n    @return: A list of The first node of linked list which have twice size\n    \"\"\"\n    def rehashing(self, hash_table):\n        if not hash_table:\n            return\n\n        CAPACITY = len(hash_table) * 2\n        heads = [None] * CAPACITY\n        tails = [None] * CAPACITY\n\n        curr = _node = i = None\n        for node in hash_table:\n            curr = node\n\n            while curr:\n                i = curr.val % CAPACITY\n                _node = ListNode(curr.val)\n\n                if heads[i]:\n                    tails[i].next = _node\n                else:\n                    heads[i] = _node\n\n                tails[i] = _node\n\n                curr = curr.next\n\n        return heads\n"
  },
  {
    "path": "lintcode/12_min_stack.py",
    "content": "class MinStack:\n    def __init__(self):\n        self.stack = []\n        self.mins = []\n\n    def push(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: void\n        \"\"\"\n        self.stack.append(x)\n\n        if not self.mins or x <= self.mins[-1]:\n            self.mins.append(x)\n\n    def pop(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        if not self.stack:\n            return -1\n\n        x = self.stack.pop()\n\n        if self.mins and x == self.mins[-1]:\n            self.mins.pop()\n\n        return x\n\n    def top(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        if not self.stack:\n            return -1\n\n        return self.stack[-1]\n\n    def min(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        if not self.mins:\n            return -1\n\n        return self.mins[-1]\n\n\n# Your MinStack object will be instantiated and called as such:\n# obj = MinStack()\n# obj.push(x)\n# obj.pop()\n# param_3 = obj.top()\n# param_4 = obj.min()\n"
  },
  {
    "path": "lintcode/130_heapify.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: Given an integer array\n    @return: nothing\n    \"\"\"\n    def heapify(self, A):\n        # start from mid-depth to sift down\n        for i in range(len(A) // 2, -1, -1):\n            self.siftdown(A, i)\n\n    def siftdown(self, A, i):\n        \"\"\"\n        sift down\n        1. pick the smaller child to swap\n        2. if parent is already small than both children, no need to continue\n        3. continue to sift down in next depth\n        \"\"\"\n        n = len(A)\n        while i * 2 + 1 < n:\n            # left child\n            _i = i * 2 + 1\n            if _i + 1 < n and A[_i + 1] < A[_i]:\n                # right child\n                _i += 1\n            if A[_i] >= A[i]:\n                # if its already steady\n                break\n\n            A[i], A[_i] = A[_i], A[i]\n            i = _i\n"
  },
  {
    "path": "lintcode/131_building_outline.py",
    "content": "\"\"\"\nthis problem familiar with `leetcode/218_the_skyline_problem.py`\nwith different output\n\"\"\"\nimport heapq\n\n\nclass HashHeapq:\n    def __init__(self):\n        self.heap = []\n        self.deleted = {}\n\n    def push(self, val):\n        heapq.heappush(self.heap, val)\n\n    def pop(self):\n        if self.is_empty():\n            return -1\n\n        return heapq.heappop(self.heap)\n\n    def remove(self, val):\n        if self.is_empty():\n            return\n\n        if val not in self.deleted:\n            self.deleted[val] = 0\n\n        self.deleted[val] += 1\n\n    def top(self):\n        if self.is_empty():\n            return -1\n\n        return self.heap[0]\n\n    def is_empty(self):\n        while self.heap and self.deleted.get(self.heap[0]):\n            val = heapq.heappop(self.heap)\n            self.deleted[val] -= 1\n\n        return not self.heap\n\n\nclass Solution:\n    def buildingOutline(self, buildings):\n        \"\"\"\n        :type buildings: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n        if not buildings:\n            return ans\n\n        time = []\n\n        for x, _x, height in buildings:\n            time.append((x, height, True))\n            time.append((_x, height, False))\n\n        time.sort()\n        heap = HashHeapq()\n        tmp = []\n\n        for x, height, is_start in time:\n            if is_start:\n                heap.push(-height)\n            else:\n                heap.remove(-height)\n\n            max_h = -heap.top() if not heap.is_empty() else 0\n\n            if tmp and tmp[-1][0] == x:\n                tmp.pop()\n            if tmp and tmp[-1][1] == max_h:\n                continue\n            tmp.append([x, max_h])\n\n        _x = pre_h = 0\n\n        for x, height in tmp:\n            if pre_h > 0:\n                ans.append([_x, x, pre_h])\n\n            _x = x\n            pre_h = height\n\n        return ans\n"
  },
  {
    "path": "lintcode/132_word_search_ii.py",
    "content": "class Solution:\n    def __init__(self):\n        self.root = self.new_node()\n        self.row_vector = [1, -1, 0, 0]\n        self.col_vector = [0, 0, 1, -1]\n\n    def new_node(self):\n        return {\n            'end_of': '',\n            'children': {}\n        }\n\n    def put(self, parent, string):\n        if not string:\n            return\n        for char in string:\n            if char in parent['children']:\n                parent = parent['children'][char]\n            else:\n                parent['children'][char] = self.new_node()\n                parent = parent['children'][char]\n        parent['end_of'] = string\n\n    \"\"\"\n    @param: board: A list of lists of character\n    @param: words: A list of string\n    @return: A list of string\n    \"\"\"\n    def wordSearchII(self, board, words):\n        if not words or len(words) < 1 \\\n                or not board or len(board) < 1 \\\n                or len(board[0]) < 1:\n            return []\n        self.m, self.n = len(board), len(board[0])\n        self.board = board\n        for word in words:\n            self.put(self.root, word)\n        result = {}\n        for row in range(self.m):\n            for col in range(self.n):\n                if board[row][col] in self.root['children']:\n                    self.find(row, col, self.root, result)\n        return result.keys()\n\n    def find(self, x, y, parent, result):\n        char = self.board[x][y]\n        if char not in parent['children']:\n            return\n        parent = parent['children'][char]\n        if parent['end_of']:\n            result[parent['end_of']] = 1\n            parent['end_of'] = ''\n\n        # To avoid returning along the original path, just simply set the last visited cell to `'#'`\n        self.board[x][y] = '#'\n        for d in range(4):\n            _x = x + self.row_vector[d]\n            _y = y + self.col_vector[d]\n            if 0 <= _x < self.m \\\n                    and 0 <= _y < self.n \\\n                    and self.board[_x][_y] in parent['children']:\n                self.find(_x, _y, parent, result)\n        self.board[x][y] = char\n"
  },
  {
    "path": "lintcode/134_lru_cache.py",
    "content": "\"\"\"\nMain Concept:\n\nDm <-> a <-> b <-> c <-> dm  |<- cache_list (dll)\n\n1. if cache is updated (set/get)\n    => move to the end of cache_list\n2. if cache is full\n    => evict the most left node in cache first,\n       that is `a` in above diagram\n    => add the new cache to the end of the cache_list as new tail\n\"\"\"\n\n\nclass LRUCache:\n    def __init__(self, capacity):\n        \"\"\"\n        :type capacity: int\n        \"\"\"\n        self.cap = capacity\n        self.nodes = {}\n        self.D = CacheNode(-1)\n        self.d = CacheNode(-1)\n        self.D.nxt = self.d\n        self.d.pre = self.D\n\n    def get(self, key):\n        \"\"\"\n        :type key: int\n        :rtype: int\n        \"\"\"\n        if key not in self.nodes:\n            return -1\n\n        self._update(key)\n        return self.nodes[key].val\n\n    def set(self, key, val):\n        \"\"\"\n        :type key: int\n        :type val: int\n        :rtype: void\n        \"\"\"\n        if self.cap <= 0:\n            return\n\n        if key in self.nodes:\n            self._update(key, val)\n            return\n\n        while len(self.nodes) >= self.cap:\n            self._evict()\n\n        self._add(key, val)\n\n    def _evict(self):\n        node = self._pop_head()\n        del self.nodes[node.key]\n\n    def _update(self, key, val=None):\n        node = self.nodes[key]\n\n        if val:\n            node.val = val\n\n        node.unlink()\n        self._add_tail(node)\n\n    def _add(self, key, val):\n        self.nodes[key] = CacheNode(key, val)\n        self._add_tail(self.nodes[key])\n\n    def _pop_head(self):\n        node = self.D.nxt\n        node.unlink()\n        return node\n\n    def _add_tail(self, node):\n        node.link(self.d.pre, self.d)\n\n\nclass CacheNode:\n    def __init__(self, key, val=None, pre=None, nxt=None):\n        self.key = key\n        self.val = val\n        self.pre = pre\n        self.nxt = nxt\n\n    def link(self, pre, nxt):\n        self.pre = pre\n        self.nxt = nxt\n        pre.nxt = self\n        nxt.pre = self\n\n    def unlink(self):\n        self.pre.nxt = self.nxt\n        self.nxt.pre = self.pre\n        self.pre = self.nxt = None\n"
  },
  {
    "path": "lintcode/135_combination_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @param: target: An integer\n    @return: A list of lists of integers\n    \"\"\"\n    def combinationSum(self, A, target):\n        ans = []\n        if not A:\n            return ans\n\n        A.sort()\n        self.dfs(A, 0, target, ans, [])\n        return ans\n\n    def dfs(self, A, start, remaining, ans, path):\n        if remaining == 0:\n            ans.append(path[:])\n            return\n\n        for i in range(start, len(A)):\n            if remaining < A[i]:\n                # note that, its `return` here\n                # since `remaining < A[i]` and `A[i] <= A[i + 1] <= ...`\n                # so once it continued, all iteration after i is no need\n                return\n\n            path.append(A[i])\n            self.dfs(A, i, remaining - A[i], ans, path)\n            path.pop()\n"
  },
  {
    "path": "lintcode/1365_minimum_cycle_section.py",
    "content": "class Solution:\n    \"\"\"\n    @param array: an integer array\n    @return: the length of the minimum cycle section\n    \"\"\"\n    def minimumCycleSection(self, array):\n        if not array:\n            return 0\n\n        n = len(array)\n\n        for size in range(1, n + 1):\n            gotcha = True\n\n            for i in range(size):\n                if any(array[i] != array[j] for j in range(i + size, n, size)):\n                    gotcha = False\n\n            if gotcha:\n                return size\n\n        return n\n"
  },
  {
    "path": "lintcode/1366_directed_graph_loop.py",
    "content": "import collections\n\n\nclass Solution:\n    \"\"\"\n    @param start: The start points set\n    @param end: The end points set\n    @return: Return if the graph is cyclic\n    \"\"\"\n    def isCyclicGraph(self, start, end):\n        if not start or not end or len(start) != len(end):\n            return False\n\n        n = len(start)\n        nxt = collections.defaultdict(set)\n        visited = set()\n        rec_stack = set()\n\n        for i in range(n):\n            nxt[start[i]].add(end[i])\n\n        for i in range(n):\n            if start[i] in visited:\n                continue\n            if self.dfs(start[i], nxt, visited, rec_stack):\n                return True\n\n        return False\n\n    def dfs(self, u, nxt, visited, rec_stack):\n        if u not in nxt:\n            return False\n\n        visited.add(u)\n        rec_stack.add(u)\n\n        for v in nxt[u]:\n            if v in rec_stack:\n                return True\n\n            if v not in visited and self.dfs(v, nxt, visited, rec_stack):\n                return True\n\n        rec_stack.discard(u)\n        return False\n"
  },
  {
    "path": "lintcode/1367_police_distance.py",
    "content": "class Solution:\n    \"\"\"\n    @param matrix : the martix\n    @return: the distance of grid to the police\n    \"\"\"\n    def policeDistance(self, matrix):\n        m, n = len(matrix), len(matrix)\n\n        POLICE = 1\n        WALL = -1\n        EMPTY = 0\n\n        ans = [[float('inf')] * n for _ in range(m)]\n        queue = []\n\n        for x in range(m):\n            for y in range(n):\n                if matrix[x][y] == WALL:\n                    ans[x][y] = -1\n                elif matrix[x][y] == POLICE:\n                    ans[x][y] = 0\n                    queue.append((x, y))\n\n        for x, y in queue:\n            for dx, dy in (\n                (-1, 0), (1, 0),\n                (0, -1), (0, 1),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if matrix[_x][_y] == WALL:\n                    continue\n                if ans[_x][_y] <= ans[x][y] + 1:\n                    continue\n\n                ans[_x][_y] = ans[x][y] + 1\n                queue.append((_x, _y))\n\n        return ans\n"
  },
  {
    "path": "lintcode/1368_same_number.py",
    "content": "class Solution:\n    \"\"\"\n    @param nums: the arrays\n    @param k: the distance of the same number\n    @return: the ans of this question\n    \"\"\"\n    def sameNumber(self, nums, k):\n        RES = ('NO', 'YES')\n\n        if not nums or not k:\n            return RES[0]\n\n        idx = {}\n        gotcha = False\n\n        for i in range(len(nums)):\n            if nums[i] in idx and i - idx[nums[i]] < k:\n                gotcha = True\n\n            idx[nums[i]] = i\n\n        return RES[int(gotcha)]\n"
  },
  {
    "path": "lintcode/136_palindrome_partitioning.py",
    "content": "class Solution:\n    ans = []\n    n = 0\n    is_palindrome = None\n\n    \"\"\"\n    @param: s: A string\n    @return: A list of lists of string\n    \"\"\"\n    def partition(self, s):\n        if not s:\n            return self.ans\n\n        self.n = len(s)\n        self.check_palindrome(s)\n        self.dfs(s, 0, [])\n\n        return self.ans\n\n    def check_palindrome(self, s):\n        \"\"\"\n        assuming string = 'aabb'\n        s: start_index, e: end_index\n\n        `is_palindrome[s][e] == T` means\n        the substring(string[s:e+1]) is a palindrome\n\n        the benefit to have the `is_palindrome` in advance is\n        we won't need to traverse the whole string again\n        when every time we need\n\n            e 0  1  2  3\n        s     a  a  b  b\n        0 a [[T, T, F, F],\n        1 a  [F, T, F, F],\n        2 b  [F, F, T, T],\n        3 b  [F, F, F, T]]\n\n        and the traversal order to init this matrix is below:\n        x: means `start > end`, its impossible\n\n        [[r1, r2, r4, r4],\n         [ x, r1, r2, r3],\n         [ x,  x, r1, r2],\n         [ x,  x,  x, r1]]\n        \"\"\"\n        self.is_palindrome = [[False] * self.n for _ in range(self.n)]\n        start = end = 0\n\n        # check the diagonal line `r1` and `r2`\n        # the traversal order is top-left -> bottom-right, see graph above\n        # since the status of `r3`, `r4`, ... depends on that\n        for end in range(self.n):\n            self.is_palindrome[end][end] = True\n\n            if end > 0:\n                start = end - 1\n                self.is_palindrome[start][end] = (s[start] == s[end])\n\n        # check the remaining triangle and traverse by line: `r3`, `r4`, ...\n        # the traversal order is bottom -> top, see graph above\n        # n - 3 = (n - 1) - 2\n        # start + 2\n        for start in range(self.n - 3, -1, -1):\n            for end in range(start + 2, self.n):\n                self.is_palindrome[start][end] = (\n                    self.is_palindrome[start + 1][end - 1]\n                    and s[start] == s[end]\n                )\n\n    # traverse all of the possible substring from start\n    # if is a palindrome, continue to traverse\n    # otherwise will be ignored\n    # and catch all result at the end\n    def dfs(self, s, start, palindromes):\n        if start >= self.n:\n            self.ans.append(palindromes)\n        next_start = 0\n        for end in range(start, self.n):\n            if self.is_palindrome[start][end]:\n                # `palindromes + [s[start:next_start]]`\n                # will create and return new list\n                next_start = end + 1\n                self.dfs(s, next_start, palindromes + [s[start:next_start]])\n"
  },
  {
    "path": "lintcode/137_clone_graph.py",
    "content": "\"\"\"\nDefinition for a undirected graph node\nclass UndirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\n\"\"\"\nIteration\n\"\"\"\nclass Solution:\n    def cloneGraph(self, node):\n        \"\"\"\n        :type node: UndirectedGraphNode\n        :rtype: UndirectedGraphNode\n        \"\"\"\n        if not node:\n            return\n\n        queue = [node]\n        root = UndirectedGraphNode(node.label)\n        N = {root.label: root}\n\n        for node in queue:\n            for neighbor in node.neighbors:\n                _node = None\n                if neighbor.label in N:\n                    _node = N[neighbor.label]\n                else:\n                    _node = UndirectedGraphNode(neighbor.label)\n                    N[neighbor.label] = _node\n                    queue.append(neighbor)\n\n                N[node.label].neighbors.append(_node)\n\n        return root\n\n\n\"\"\"\nRecursion\n\"\"\"\nclass Solution:\n    def cloneGraph(self, node):\n        \"\"\"\n        :type node: UndirectedGraphNode\n        :rtype: UndirectedGraphNode\n        \"\"\"\n        if not node:\n            return\n\n        return self.dfs(node, {})\n\n    def dfs(self, node, N):\n        if node.label in N:\n            return N[node.label]\n\n        N[node.label] = UndirectedGraphNode(node.label)\n        for neighbor in node.neighbors:\n            N[node.label].neighbors.append(self.dfs(neighbor, N))\n\n        return N[node.label]\n"
  },
  {
    "path": "lintcode/138_subarray_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: A list of integers\n    @return: A list of integers includes the index of the first number and the index of the last number\n    \"\"\"\n    def subarraySum(self, nums):\n        \"\"\"\n        len(nums) == 5\n        if `A[1] + A[2] + A[3] == 0`\n        the cumulative sum in the `i == 3` iteration\n        is same as the cumulative sum in `A[0]`\n\n        => save every sum in hashmap\n        => if got the same sum in following iteration\n        => start = hashmap[sum] + 1, end = i\n        \"\"\"\n        if not nums:\n            return []\n\n        sum_to_index = {}\n        sum_to_index[0] = -1\n\n        prefix_sum = 0\n        for i in range(len(nums)):\n            prefix_sum += nums[i]\n\n            if prefix_sum in sum_to_index:\n                return [\n                    sum_to_index[prefix_sum] + 1,\n                    i\n                ]\n\n            sum_to_index[prefix_sum] = i\n\n        return []\n"
  },
  {
    "path": "lintcode/139_subarray_sum_closest.py",
    "content": "from collections import namedtuple\n\nPair = namedtuple('Pair', ['sum', 'index'])\n\nclass Solution:\n    \"\"\"\n    @param: nums: A list of integers\n    @return: A list of integers includes the index of the first number and the index of the last number\n    \"\"\"\n    def subarraySumClosest(self, nums):\n        \"\"\"\n        Prefix Sum\n        prefix_sum[i] means the culmulative sum before `i + 1` in `nums`\n        => if we want to know the sum of [1, 2]\n        => sum(nums[1:3]) == sum(nums[0:3]) - sum(nums[0:0])\n        \"\"\"\n        ans = [0] * 2\n        if not nums:\n            return ans\n\n        n = len(nums)\n        if n == 1:\n            return ans\n\n        prefix_sum = [0] * n\n\n        prefix_sum[0] = Pair(nums[0], 0)\n        for i in range(1, n):\n            prefix_sum[i] = Pair(prefix_sum[i - 1].sum + nums[i], i)\n\n        # since the closest sum occurred when the sum is closest\n        # so we can simply calculate the difference\n        # between every two adjacent indexes\n        prefix_sum.sort(key=lambda p: p.sum)\n\n        closest_sum = float('inf')\n        tmp_sum = 0\n        for i in range(1, n):\n            # calculate all the closest sum occurred in two adjacent indexes\n            tmp_sum = prefix_sum[i].sum - prefix_sum[i - 1].sum\n\n            # keep finding the minimum closest sum\n            if tmp_sum >= closest_sum:\n                continue\n\n            closest_sum = tmp_sum\n            ans = sorted([prefix_sum[i].index, prefix_sum[i - 1].index])\n\n        # sum(nums[1:3]) == sum(nums[0:3]) - sum(nums[0:0])\n        # so start need `+1`\n        ans[0] += 1\n        return ans\n"
  },
  {
    "path": "lintcode/13_strstr.py",
    "content": "class Solution:\n    def strStr(self, haystack, needle):\n        \"\"\"\n        :type haystack: str\n        :type needle: str\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = -1\n        if haystack is None or needle is None:\n            return NOT_FOUND\n        if haystack == needle:\n            return 0\n\n        m, n = len(haystack), len(needle)\n\n        for i in range(m - n + 1):\n            if haystack[i:i + n] == needle:\n                return i\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/141_sqrtx.py",
    "content": "class Solution:\n    def sqrt(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        if not x or x <= 1:\n            return x\n\n        left, right = 0, x\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            square = mid * mid\n\n            if square == x:\n                return mid\n\n            if square < x:\n                left = mid\n            else:\n                right = mid\n\n        return left\n"
  },
  {
    "path": "lintcode/142_o1_check_power_of_2.py",
    "content": "class Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: True or false\n    \"\"\"\n    def checkPowerOf2(self, n):\n        if not n or n <= 0:\n            return False\n\n        return n & (n - 1) == 0\n"
  },
  {
    "path": "lintcode/143_sort_colors_ii.py",
    "content": "\"\"\"\nRainbow Sort\ntime: O(nlogk)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: colors: A list of integer\n    @param: k: An integer\n    @return: nothing\n    \"\"\"\n    def sortColors2(self, colors, k):\n        if not colors or not k:\n            return\n        self.rainbow_sort(colors, 0, len(colors) - 1, 1, k)\n\n    def rainbow_sort(self, colors, start, end, color_from, color_to):\n        \"\"\"\n        like quick sort\n        \"\"\"\n        if color_from >= color_to:\n            return\n        if start >= end:\n            return\n\n        left, right = start, end\n        color_mid = (color_from + color_to) // 2\n        while left <= right:\n            while left <= right and colors[left] <= color_mid:\n                left += 1\n            while left <= right and colors[right] > color_mid:\n                right -= 1\n            if left <= right:\n                colors[left], colors[right] = colors[right], colors[left]\n                left += 1\n                right -= 1\n\n        self.rainbow_sort(colors, start, right, color_from, color_mid)\n        self.rainbow_sort(colors, left, end, color_mid + 1, color_to)\n\n\n\"\"\"\nTLE\nExtend from sort color\ntime: O(nk)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: colors: A list of integer\n    @param: k: An integer\n    @return: nothing\n    \"\"\"\n    def sortColors2(self, colors, k):\n        \"\"\"\n        1. ensure the `min_color` in the `left_scope`,\n           and the `max_color` in the `right_scope`\n           in every iteration\n        2. keep sorting the `mid_scope` to\n           pick min/max color to the left/right scope\n        \"\"\"\n        count = 0\n        n = len(colors)\n        left, right = 0, n - 1\n        i = _min = _max = 0\n\n        while count < k:\n            _min = _max = colors[left]\n            for i in range(left + 1, right + 1):\n                if colors[i] < _min:\n                    _min = colors[i]\n                if colors[i] > _max:\n                    _max = colors[i]\n\n            i = left\n            while i <= right:\n                if colors[i] == _min:\n                    colors[left], colors[i] = colors[i], colors[left]\n                    left += 1\n                    i += 1\n                elif _min < colors[i] < _max:\n                    # leave it to\n                    # the next iteration of `while count < k` to sort\n                    i += 1\n                else:\n                    colors[i], colors[right] = colors[right], colors[i]\n                    right -= 1\n\n            count += 2\n"
  },
  {
    "path": "lintcode/148_sort_colors.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: A list of integer which is 0, 1 or 2\n    @return: nothing\n    \"\"\"\n    def sortColors(self, A):\n        if not A:\n            return\n\n        left, right = 0, len(A) - 1\n        i = 0\n        while i <= right:\n            if A[i] == 0:\n                A[left], A[i] = A[i], A[left]\n                left += 1\n                i += 1\n            elif A[i] == 1:\n                \"\"\"\n                temply ignore it\n                it will be swapped if there is `0` later\n                \"\"\"\n                i += 1\n            else:\n                \"\"\"\n                cannot `i += 1` since the swapped value still need to check\n                \"\"\"\n                A[right], A[i] = A[i], A[right]\n                right -= 1\n"
  },
  {
    "path": "lintcode/149_best_time_to_buy_and_sell_stock.py",
    "content": "class Solution:\n    \"\"\"\n    @param: P: Given an integer array\n    @return: Maximum profit\n    \"\"\"\n    def maxProfit(self, P):\n        ans = 0\n        if not P:\n            return ans\n\n        Pmin = P[0]\n\n        for i in range(1, len(P)):\n            if P[i] - Pmin > ans:\n                ans = P[i] - Pmin\n            if P[i] < Pmin:\n                Pmin = P[i]\n\n        return ans\n"
  },
  {
    "path": "lintcode/14_first_position_of_target.py",
    "content": "class Solution:\n    # @param A: The integer array\n    # @param target: Target number to find\n    # @return the first position of target in A, position start from 0\n    def binarySearch(self, A, target):\n        if not A:\n            return -1\n\n        left, mid, right = 0, 0, len(A) - 1\n\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] < target:\n                left = mid\n            else:\n                right = mid\n\n        if A[left] == target:\n            return left\n        elif A[right] == target:\n            return right\n\n        return -1\n"
  },
  {
    "path": "lintcode/150_best_time_to_buy_and_sell_stock_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: P: Given an integer array\n    @return: Maximum profit\n    \"\"\"\n    def maxProfit(self, P):\n        ans = 0\n        if not P:\n            return ans\n\n        for i in range(1, len(P)):\n            if P[i] > P[i - 1]:\n                ans += P[i] - P[i - 1]\n\n        return ans\n"
  },
  {
    "path": "lintcode/151_best_time_to_buy_and_sell_stock_iii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: P: Given an integer array\n    @return: Maximum profit\n    \"\"\"\n    def maxProfit(self, P):\n        if not P:\n            return 0\n\n        K = 2\n        STAGE = 2 * K + 1\n\n        \"\"\"\n        `dp[i][j]` means the `i`th day at the `j`th stage\n        stage 0: before the first buying\n        stage 1: holding the first stock\n        stage 2: after the first selling, before the second buying\n        stage 3: holding the second stock\n        stage 4: after the second selling\n\n        note that, `dp[i][0]` means always stay in stage 0,\n        so its never going to be profitable\n        \"\"\"\n        dp = [[0] * STAGE for _ in range(2)]\n\n        i = j = prev = curr = profit = 0\n        for i in range(1, len(P)):\n            prev = curr\n            curr = 1 - curr\n            profit = P[i] - P[i - 1]\n            for j in range(1, STAGE, 2):\n                \"\"\"\n                in stage 1 and 3, holding a stock\n                profit comes from:\n                1. still holding a stock yesterday,\n                   and gains profit (may be negative) today\n                2. holding no any stock yesterday,\n                   just makes a buying today, so no profit\n                choose the maximum\n                \"\"\"\n                dp[curr][j] = max(dp[prev][j] + profit, dp[prev][j - 1])\n            for j in range(2, STAGE, 2):\n                \"\"\"\n                in stage 2 and 4, holding no any stock\n                profit comes from:\n                1. still holding no any stock yesterday,\n                   just makes a buying today, so no profit\n                2. holding a stock yesterday,\n                   and gains profit (may be negative) today\n                choose the maximum\n                \"\"\"\n                dp[curr][j] = max(dp[prev][j], dp[prev][j - 1] + profit)\n\n        return max(dp[curr])\n"
  },
  {
    "path": "lintcode/153_combination_sum_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: Given the candidate numbers\n    @param: target: Given the target number\n    @return: All the combinations that sum to target\n    \"\"\"\n    def combinationSum2(self, A, target):\n        ans = []\n        if not A:\n            return ans\n\n        A.sort()\n        self.dfs(A, 0, target, ans, [])\n        return ans\n\n    def dfs(self, A, start, remaining, ans, path):\n        if remaining == 0:\n            ans.append(path[:])\n            return\n\n        for i in range(start, len(A)):\n            if remaining < A[i]:\n                return\n\n            # to prevent [1', 2, 5] and [1\", 2, 5]\n            # appear in result at same time\n            if i > start and A[i] == A[i - 1]:\n                continue\n\n            path.append(A[i])\n            self.dfs(A, i + 1, remaining - A[i], ans, path)\n            path.pop()\n"
  },
  {
    "path": "lintcode/154_regular_expression_matching.py",
    "content": "\"\"\"\nMain Concept:\n\nend by '*' and has no matched\ncase 1-1: `P[j-2:j]` is `c*` and have no matched in `S`\n=> `j-2` in `dp[i][j-2]` means ignored `c` and `*`\n\nend by `*` and is the last matched in `*`\ncase 1-2: `P[j-2:j]` is `.*` and `.` always matched `S[i-1]`\ncase 1-3: `P[j-2:j]` is `a*` and `a` == `P[j-2]` == `S[i-1]`\n=> `i-1` in `dp[i-1][j]` means to check the `?` below\n    '...a?a'\n         \\|\n    '...xa*'\n\ncase 2: `P[j-1]` is `.` and `.` always matched `S[i-1]`\ncase 3: `P[j-1]` is `a` and `a` == `P[j-1]` == `S[i-1]`\n=> `-1` in `dp[i-1][j-1]` means previous char\n\"\"\"\n\n\nclass Solution:\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: bool\n        \"\"\"\n        if s == p == '':\n            return True\n\n        m, n = len(s), len(p)\n        MULTI = '*'\n        ANY = '.'\n\n        \"\"\"\n        `dp[i][j]` means the substr end at `s[i - 1]` was matched by\n        the substr end at `p[j - 1]`\n        \"\"\"\n        dp = [[False] * (n + 1) for _ in range(m + 1)]\n        dp[0][0] = True\n        # dp[i][0] = False  # i = 1 -> m + 1\n        # dp[0][j] -> ?, need to check\n\n        for i in range(m + 1):\n            for j in range(1, n + 1):\n                if i > 0 and p[j - 1] == s[i - 1] and dp[i - 1][j - 1]:\n                    dp[i][j] = True\n                elif i > 0 and p[j - 1] == ANY and dp[i - 1][j - 1]:\n                    dp[i][j] = True\n                elif j > 1 and p[j - 1] == MULTI:\n                    if dp[i][j - 2]:\n                        dp[i][j] = True\n                    elif i > 0 and p[j - 2] == s[i - 1] and dp[i - 1][j]:\n                        dp[i][j] = True\n                    elif i > 0 and p[j - 2] == ANY and dp[i - 1][j]:\n                        dp[i][j] = True\n\n        return dp[m][n]\n"
  },
  {
    "path": "lintcode/155_minimum_depth_of_binary_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: The root of binary tree\n    @return: An integer\n    \"\"\"\n    def minDepth(self, root):\n        ans = 0\n        if not root:\n            return ans\n\n        queue = [root]\n        while queue:\n            _queue = []\n            ans += 1\n\n            for node in queue:\n                if not node.left and not node.right:\n                    return ans\n                if node.left:\n                    _queue.append(node.left)\n                if node.right:\n                    _queue.append(node.right)\n\n            queue = _queue\n\n        return ans\n\n\nclass Solution:\n    \"\"\"\n    @param: root: The root of binary tree\n    @return: An integer\n    \"\"\"\n    def minDepth(self, root):\n        if not root:\n            return 0\n\n        if not root.left and not root.right:\n            return 1\n\n        left = self.minDepth(root.left)\n        right = self.minDepth(root.right)\n\n        if left == 0:\n            return right + 1\n        if right == 0:\n            return left + 1\n\n        return min(left, right) + 1\n"
  },
  {
    "path": "lintcode/156_merge_intervals.py",
    "content": "\"\"\"\nDefinition of Interval.\nclass Interval(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n\"\"\"\n\n\nclass Solution:\n    def merge(self, intvs):\n        \"\"\"\n        :type intvs: List[Interval]\n        :rtype: List[Interval]\n        \"\"\"\n        ans = []\n        if not intvs:\n            return ans\n\n        intvs.sort(key=lambda intv: (intv.start, intv.end))\n\n        for intv in intvs:\n            if not ans or intv.start > ans[-1].end:\n                ans.append(intv)\n            elif intv.end > ans[-1].end:\n                ans[-1].end = intv.end\n\n        return ans\n"
  },
  {
    "path": "lintcode/158_two_strings_are_anagrams.py",
    "content": "class Solution:\n    \"\"\"\n    @param s: The first string\n    @param b: The second string\n    @return true or false\n    \"\"\"\n    def anagram(self, s, t):\n        if s == '' and t == '':\n            return True\n        if not s or not t:\n            return False\n\n        s = sorted(s)\n        t = sorted(t)\n\n        return s == t\n"
  },
  {
    "path": "lintcode/159_find_minimum_in_rotated_sorted_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: a rotated sorted array\n    @return: the minimum number in the array\n    \"\"\"\n    def findMin(self, nums):\n        if not nums:\n            return -1\n\n        l, m, r = 0, 0, len(nums) - 1\n\n        \"\"\"\n        since the children between `nums[0:maximum]`\n        are all great than `nums[minimum:-1]`\n        so we can pick the last child, and do the binary searching, if:\n        1. child in `nums[0:maximum]`,\n           then the left boundary will continue to move to the maximum\n        2. child in `nums[minimum:-1]`,\n           then the right boundary will to the minimum\n        \"\"\"\n        last = nums[-1]\n\n        while l + 1 < r:\n            m = l + (r - l) // 2\n            if nums[m] > last:\n                l = m\n            else:\n                r = m\n\n        return min(nums[l], nums[r])\n"
  },
  {
    "path": "lintcode/15_permutations.py",
    "content": "class Solution:\n    def permute(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: list[list[int]]\n        \"\"\"\n        if not nums:\n            return [[]]\n\n        ans = []\n\n        nums.sort()\n        self.dfs(nums, ans, [])\n\n        return ans\n\n    def dfs(self, nums, ans, path):\n        if not nums:\n            ans.append(path[:])\n            return\n\n        for i in range(len(nums)):\n            path.append(nums[i])\n            self.dfs(nums[:i] + nums[i + 1:], ans, path)\n            path.pop()\n"
  },
  {
    "path": "lintcode/160_find_minimum_in_rotated_sorted_array_ii.py",
    "content": "\"\"\"\nIteration\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: a rotated sorted array\n    @return: the minimum number in the array\n    \"\"\"\n    def findMin(self, A):\n        if not A:\n            return -1\n\n        _min = A[0]\n        for i in range(1, len(A)):\n            if A[i] < _min:\n                _min = A[i]\n                break\n\n        return _min\n\n\n\"\"\"\nBinary Searching\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: a rotated sorted array\n    @return: the minimum number in the array\n    \"\"\"\n    def findMin(self, A):\n        \"\"\"\n        all chilren before the pivot are great than or equal the child at end\n        all chilren after the pivot are less than or equal the child at end\n        \"\"\"\n        if not A:\n            return -1\n\n        left, right = 0, len(A) - 1\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if A[mid] == A[right]:\n                # means it's ok to remove the end child\n                right -= 1\n            elif A[mid] < A[right]:\n                # mid at the right side of pivot\n                right = mid\n            else:\n                # mid at the left side of pivot\n                left = mid\n\n        return A[left] if A[left] < A[right] else A[right]\n"
  },
  {
    "path": "lintcode/165_merge_two_sorted_lists.py",
    "content": "# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\n\nclass Solution:\n    def mergeTwoLists(self, a, b):\n        \"\"\"\n        :type a: ListNode\n        :type b: ListNode\n        :rtype: ListNode\n        \"\"\"\n        dummy = tail = ListNode(-1)\n\n        while a and b:\n            if a.val < b.val:\n                tail.next = ListNode(a.val)\n                a = a.next\n            else:\n                tail.next = ListNode(b.val)\n                b = b.next\n            tail = tail.next\n\n        while a:\n            tail.next = ListNode(a.val)\n            a = a.next\n            tail = tail.next\n\n        while b:\n            tail.next = ListNode(b.val)\n            b = b.next\n            tail = tail.next\n\n        return dummy.next\n"
  },
  {
    "path": "lintcode/167_add_two_numbers.py",
    "content": "\"\"\"\nDefinition for singly-linked list.\nclass ListNode:\n    def __init__(self, x):\n        self.val = x\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    def addLists(self, A, B):\n        \"\"\"\n        :type A: ListNode\n        :type B: ListNode\n        :rtype: ListNode\n        \"\"\"\n        dummy = tail = ListNode(-1)\n        carry = 0\n\n        while A and B:\n            carry += A.val + B.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            tail = tail.next\n            A = A.next\n            B = B.next\n\n        while A:\n            carry += A.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            tail = tail.next\n            A = A.next\n\n        while B:\n            carry += B.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            tail = tail.next\n            B = B.next\n\n        if carry:\n            tail.next = ListNode(carry)\n\n        return dummy.next\n"
  },
  {
    "path": "lintcode/168_burst_balloons.py",
    "content": "class Solution:\n    \"\"\"\n    @param: V: A list of integer\n    @return: An integer, maximum coins\n    \"\"\"\n    def maxCoins(self, V):\n        if not V:\n            return 0\n\n        \"\"\"\n        the value of last balloons is `1 * v * 1`\n        \"\"\"\n        V = [1] + V + [1]\n\n        n = len(V)\n\n        \"\"\"\n        `dp[i][j]` means the maximum value when\n        all the balloons in [i+1, j-1] was bursted\n        \"\"\"\n        dp = [[0] * n for _ in range(n)]\n        # pi = [[0] * n for _ in range(n)]\n\n        for i in range(n - 1 - 2, -1, -1):\n            for j in range(i + 2, n):\n\n                \"\"\"\n                leave last balloon `k` to burst\n                `i + 1 <= k <= j - 1`\n                \"\"\"\n                for k in range(i + 1, j):\n                    dp[i][j] = max(\n                        dp[i][j],\n                        dp[i][k] + dp[k][j] + V[i] * V[k] * V[j]\n                    )\n                    # if dp[i][j] == dp[i][k] + dp[k][j] + V[i] * V[k] * V[j]:\n                    #     pi[i][j] = k\n\n        # self.print_paths(0, n - 1, V, pi)\n\n        return dp[0][n - 1]\n\n    # def print_paths(self, i, j, V, pi):\n    #     if i + 1 == j:\n    #         return\n\n    #     self.print_paths(i, pi[i][j], V, pi)\n    #     self.print_paths(pi[i][j], j, V, pi)\n\n    #     print(\"burst {vk}, get coins {vi} * {vk} * {vj} = {vsum}\".format(\n    #         vi=V[i],\n    #         vk=V[pi[i][j]],\n    #         vj=V[j],\n    #         vsum=V[i] * V[pi[i][j]] * V[j]\n    #     ))\n"
  },
  {
    "path": "lintcode/16_permutations_ii.py",
    "content": "class Solution:\n    \"\"\"\n    dfs with ignoring self and same num\n    \"\"\"\n    def permuteUnique(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n\n        if not nums:\n            return [[]]\n\n        ans = []\n\n        nums.sort()\n        self.dfs(nums, ans, [])\n\n        return ans\n\n    def dfs(self, nums, ans, path):\n        if not nums:\n            ans.append(path[:])\n            return\n\n        for i in range(len(nums)):\n            \"\"\"\n            ignore same num\n            \"\"\"\n            if i > 0 and nums[i] == nums[i - 1]:\n                continue\n\n            \"\"\"\n            ignore self\n            \"\"\"\n            path.append(nums[i])\n            self.dfs(nums[:i] + nums[i + 1:], ans, path)\n            path.pop()\n\n\nclass Solution:\n    \"\"\"\n    dfs with visited indices\n    \"\"\"\n    def permuteUnique(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n\n        if not nums:\n            return [[]]\n\n        ans = []\n        visited = [False] * len(nums)\n\n        nums.sort()\n        self.dfs(nums, visited, ans, [])\n\n        return ans\n\n    def dfs(self, nums, visited, ans, path):\n        if len(path) == len(nums):\n            ans.append(path[:])\n            return\n\n        for i in range(len(nums)):\n            if visited[i]:\n                continue\n\n            \"\"\"\n            example: [0, 3, 3', 3\"]\n            if current iteration is `3\"`\n            we need to ensure `3`, `3'` is picked\n            otherwise repeated result will be included\n            \"\"\"\n            if i > 0 and not visited[i - 1] and nums[i] == nums[i - 1]:\n                continue\n\n            visited[i] = True\n            path.append(nums[i])\n            self.dfs(nums, visited, ans, path)\n            visited[i] = False\n            path.pop()\n"
  },
  {
    "path": "lintcode/171_anagrams.py",
    "content": "class Solution:\n    \"\"\"\n    @param: S: A list of strings\n    @return: A list of strings\n    \"\"\"\n    def anagrams(self, S):\n        ans = []\n        if not S:\n            return ans\n\n        D = {}\n        for s in S:\n            _s = ''.join(sorted(s))\n            if _s not in D:\n                D[_s] = []\n            D[_s].append(s)\n\n        for k, S in D.items():\n            if len(S) > 1:\n                ans.extend(S)\n\n        return ans\n"
  },
  {
    "path": "lintcode/175_invert_binary_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: a TreeNode, the root of the binary tree\n    @return: nothing\n    \"\"\"\n    def invertBinaryTree(self, root):\n        self.divide_conquer(root)\n\n    def divide_conquer(self, node):\n        if not node:\n            return\n\n        self.divide_conquer(node.left)\n        self.divide_conquer(node.right)\n\n        node.left, node.right = node.right, node.left\n"
  },
  {
    "path": "lintcode/178_graph_valid_tree.py",
    "content": "class Solution:\n    def validTree(self, n, edges):\n        \"\"\"\n        :type n: int\n        :type edges: list[int]\n        :rtype: bool\n        \"\"\"\n        if len(edges) != n - 1:\n            return False\n\n        nodes = [i for i in range(n)]\n\n        for a, b in edges:\n            _a = self.find(nodes, a)\n            _b = self.find(nodes, b)\n\n            if _a is _b:\n                return False\n\n            nodes[_a] = _b\n\n        return True\n\n    def find(self, nodes, a):\n        if nodes[a] is a:\n            return a\n\n        nodes[a] = self.find(nodes, nodes[a])\n        return nodes[a]\n"
  },
  {
    "path": "lintcode/17_subsets.py",
    "content": "\"\"\"\nDFS\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A set of numbers\n    @return: A list of lists\n    \"\"\"\n    def subsets(self, A):\n        if not A:\n            return [[]]\n\n        ans = []\n        self.dfs(sorted(A), 0, ans, [])\n        return ans\n\n    def dfs(self, A, start, ans, subset):\n        ans.append(subset[:])\n\n        if start >= len(A):\n            return\n\n        for i in range(start, len(A)):\n            self.dfs(A, i + 1, ans, subset + [A[i]])\n\n\n\"\"\"\nBit Manipulation\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A set of numbers\n    @return: A list of lists\n    \"\"\"\n    def subsets(self, A):\n        if not A:\n            return [[]]\n\n        ans = []\n        n = len(A)\n\n        A.sort()\n\n        for i in range(1 << n):\n            subset = []\n            for j in range(n):\n                \"\"\"\n                check `j`th digit in `bin(i)`\n\n                example:\n                i == 011\n                j == 0 => 1 << 0 == 001 => 011 & 001 == 1\n                j == 1 => 1 << 1 == 010 => 011 & 010 == 1\n                j == 2 => 1 << 2 == 100 => 011 & 100 == 0\n                \"\"\"\n                if i & (1 << j):\n                    subset.append(A[j])\n\n            ans.append(subset)\n\n        return ans\n"
  },
  {
    "path": "lintcode/183_wood_cut.py",
    "content": "class Solution:\n    \"\"\"\n    @param: L: Given n pieces of wood with length L[i]\n    @param: k: An integer\n    @return: The maximum length of the small pieces\n    \"\"\"\n    def woodCut(self, L, k):\n        \"\"\"\n        Assuming the `m` is the maximum length\n        len   | ... m-2 m-1 m m+1 m+2 ...\n        check |  T   T   T  T  F   F   F\n        * check: is it ok to cut into at least `k` pieces\n        \"\"\"\n        if not L or not k:\n            return 0\n\n        left = 1\n        total_len = right = L[0]\n        for i in range(1, len(L)):\n            if L[i] > right:\n                right = L[i]\n\n            total_len += L[i]\n\n        if total_len < k:\n            return 0\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if self.check_if_possible(L, mid, k):\n                left = mid\n            else:\n                right = mid\n\n        return right if self.check_if_possible(L, right, k) else left\n\n    def check_if_possible(self, L, size, max_pieces):\n        pieces = 0\n\n        for i in range(len(L)):\n            pieces += L[i] // size\n            if pieces >= max_pieces:\n                return True\n\n        return False\n"
  },
  {
    "path": "lintcode/18_subsets_ii.py",
    "content": "\"\"\"\nDFS\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A set of numbers.\n    @return: A list of lists. All valid subsets.\n    \"\"\"\n    def subsetsWithDup(self, A):\n        if not A:\n            return [[]]\n\n        ans = []\n        self.dfs(sorted(A), 0, ans, [])\n        return ans\n\n    def dfs(self, A, start, ans, subset):\n        ans.append(subset[:])\n\n        if start >= len(A):\n            return\n\n        for i in range(start, len(A)):\n            if i - 1 >= start and A[i] == A[i - 1]:\n                continue\n\n            self.dfs(A, i + 1, ans, subset + [A[i]])\n\n            \"\"\"\n            backtracking if using same list\n            \"\"\"\n            # subset.append(A[i])\n            # self.dfs(A, i + 1, ans, subset)\n            # subset.pop()\n"
  },
  {
    "path": "lintcode/190_next_permutation_ii.py",
    "content": "class Solution:\n    def nextPermutation(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: list[int]\n        \"\"\"\n        if not nums or len(nums) < 2:\n            return nums\n\n        n = len(nums)\n        i = n - 2\n        while i >= 0 and nums[i] >= nums[i + 1]:\n            i -= 1\n\n        if i >= 0:\n            j = n - 1\n            while i < j and nums[i] >= nums[j]:\n                j -= 1\n            nums[i], nums[j] = nums[j], nums[i]\n\n        i = i + 1\n        j = n - 1\n        while i < j:\n            nums[i], nums[j] = nums[j], nums[i]\n            i += 1\n            j -= 1\n"
  },
  {
    "path": "lintcode/191_maximum_product_subarray.py",
    "content": "\"\"\"\nsince the fact:\n    the minimum negative number * -1 -> the maximum\n    the maximum positive number -> the maximum\nso we need record the minimum and the maximum number for each child in nums\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of integers\n    @return: An integer\n    \"\"\"\n    def maxProduct(self, A):\n        if not A:\n            return 0\n\n        ans = Pmin = Pmax = A[0]\n        for i in range(1, len(A)):\n            \"\"\"\n            adding `A[i]` to reset `min` and `max`\n            if its so lowest or highest\n            \"\"\"\n            C = (A[i], Pmin * A[i], Pmax * A[i])\n            Pmin, Pmax = min(C), max(C)\n\n            if Pmax > ans:\n                ans = Pmax\n\n        return ans\n"
  },
  {
    "path": "lintcode/192_wildcard_matching.py",
    "content": "\"\"\"\nMain Concept:\n\ncase 1-1: `dp[i-1][j]` means `*` may start to matched new char\n=> `i-1` in `dp[i-1][j]` means to check the `?` below\n    '...a?a'\n         \\|\n    '...xa*'\n\ncase 1-2: `dp[i][j-1]` means `*` continue to matched same char\n=> `j-1` in `dp[i][j-1]` means to check the `?` below\n    '...aa?'\n         /\n    '...xa*'\n\ncase 2: `P[j-1]` is `.` and `.` always matched `S[i-1]`\ncase 3: `P[j-1]` is `a` and `a` == `P[j-1]` == `S[i-1]`\n\n=> `-1` in `dp[i-1][j-1]` means previous char\n\"\"\"\n\n\nclass Solution:\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str, target string\n        :type p: str, regex\n        :rtype: bool\n        \"\"\"\n        if s is None or p is None:\n            return False\n        if s == '' and p == '':\n            return True\n\n        ANY = '?'\n        ANY_MULTI = '*'\n        m, n = len(s), len(p)\n\n        \"\"\"\n        `dp[i][j]` means the substr end at `S[i - 1]` was matched by\n        the substr end at `P[j - 1]`\n        \"\"\"\n        dp = [[False] * (n + 1) for _ in range(m + 1)]\n        dp[0][0] = True\n        # dp[i][0] = False\n        # dp[0][j] -> need to check\n\n        for i in range(m + 1):\n            for j in range(1, n + 1):\n                if p[j - 1] == ANY_MULTI:\n                    dp[i][j] = dp[i - 1][j] or dp[i][j - 1]\n                elif p[j - 1] == ANY and dp[i - 1][j - 1]:\n                    dp[i][j] = True\n                elif p[j - 1] == s[i - 1] and dp[i - 1][j - 1]:\n                    dp[i][j] = True\n\n        return dp[m][n]\n"
  },
  {
    "path": "lintcode/196_find_the_missing_number.py",
    "content": "class Solution:\n    def findMissing(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        ans = n = len(nums)\n\n        for i in range(n):\n            ans ^= i ^ nums[i]\n\n        return ans\n\n\nclass Solution:\n    def findMissing(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        nums.sort()\n\n        for i in range(len(nums)):\n            if i != nums[i]:\n                return i\n\n        return i + 1\n"
  },
  {
    "path": "lintcode/197_permutation_index.py",
    "content": "\"\"\"\nhttps://segmentfault.com/a/1190000004683277\n\nin the origin/unsorted `A`,\nif there are `cnt` child after and less than `A[i]`,\nmeaning there are `cnt * (n - i - 1)!` permutations\nbefore `A[i]`.\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of integers\n    @return: A long integer\n    \"\"\"\n    def permutationIndex(self, A):\n        ans = 1\n        if not A:\n            return ans\n\n        n = len(A)\n        factorial = 1\n\n        for i in range(n - 1, -1, -1):\n            cnt = 0\n            for j in range(i + 1, n):\n                if A[i] > A[j]:\n                    cnt += 1\n\n            \"\"\"\n            use the `factorial` from previous iteration `i + 1`\n            that is, `(n - i - 1)! = (n - (i + 1))!`\n            \"\"\"\n            ans += cnt * factorial\n            factorial *= n - i\n\n        return ans\n"
  },
  {
    "path": "lintcode/198_permutation_index_ii.py",
    "content": "\"\"\"\nhttps://segmentfault.com/a/1190000004683277\n\nif there are `dups`, dividing `factorial` with `dup_fact`\ne.g., 3 `A[i]`s and 4 `A[j]`s in `A`\n`dup_fact = 3! * 4!`\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of integers\n    @return: A long integer\n    \"\"\"\n    def permutationIndexII(self, A):\n        ans = 1\n        if not A:\n            return ans\n\n        n = len(A)\n        factorial = dup_fact = 1\n        dups = {}\n\n        for i in range(n - 1, -1, -1):\n            dups[A[i]] = dups.get(A[i], 0) + 1\n            dup_fact *= dups[A[i]]\n\n            cnt = 0\n            for j in range(i + 1, n):\n                if A[i] > A[j]:\n                    cnt += 1\n\n            ans += cnt * factorial // dup_fact\n            factorial *= n - i\n\n        return ans\n"
  },
  {
    "path": "lintcode/1_a_b_problem.py",
    "content": "class Solution:\n    \"\"\"\n    @param: a: An integer\n    @param: b: An integer\n    @return: The sum of a and b\n    \"\"\"\n    def aplusb(self, a, b):\n        if not a:\n            return b\n        if not b:\n            return a\n\n        INT_RANGE = 0xFFFFFFFF\n\n        while b != 0:\n            a, b = a ^ b, (a & b) << 1\n            a &= INT_RANGE\n\n        return a if a >> 31 <= 0 else a ^ ~INT_RANGE\n"
  },
  {
    "path": "lintcode/204_singleton.py",
    "content": "class Solution:\n    instance = None\n\n    # @return: The same instance of this class every time\n    @classmethod\n    def getInstance(cls):\n        if not cls.instance:\n            cls.instance = Solution()\n        return cls.instance\n"
  },
  {
    "path": "lintcode/211_string_permutation.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: a string\n    @param: B: a string\n    @return: a boolean\n    \"\"\"\n    def Permutation(self, A, B):\n        if A is '' and B is '':\n            return True\n        if not A or not B:\n            return False\n\n        cnts = {}\n        for char in A:\n            cnts[char] = cnts.get(char, 0) + 1\n        for char in B:\n            if char not in cnts or cnts[char] == 0:\n                return False\n            cnts[char] -= 1\n        for cnt in cnts.values():\n            if cnt != 0:\n                return False\n\n        return True\n"
  },
  {
    "path": "lintcode/215_rate_limiter.py",
    "content": "import collections\n\n\nclass Solution:\n    \"\"\"\n    maintain a list to record the timestamps for every event\n    and if a query coming => we need ensure\n    there is no more `freq` logs between `begin_time` and `timestamp`(current)\n\n    1. split rate\n    2. cal begin time\n    3. do binary searching to find the closest index of `begin time`\n    4. count the child between res of (3) to the end of list\n    5. if cnt >= freq => is limited\n    \"\"\"\n    def __init__(self):\n        self.times = {\n            's': 1,\n            'm': 60,\n            'h': 3600,\n            'd': 86400,\n        }\n        self.logs = collections.defaultdict(list)\n\n    def isRatelimited(self, timestamp, event, rate, increment):\n        \"\"\"\n        :type timestamp: int\n        :type event: str\n        :type rate: str\n        :type increment: bool\n        :rtype: bool\n        \"\"\"\n        if '/' not in rate:\n            return False\n\n        freq, t = rate.split('/')\n        freq = int(freq)\n        begin_time = timestamp - self.times.get(t, 1) + 1\n        is_limited = self.check_limited(event, freq, begin_time)\n\n        if increment and not is_limited:\n            self.logs[event].append(timestamp)\n\n        return is_limited\n\n    def check_limited(self, event, freq, begin_time):\n        logs = self.logs[event]\n\n        if not logs or logs[-1] < begin_time:\n            # if freq is 0 => is limited\n            return freq == 0\n\n        left, right = 0, len(logs) - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n\n            if logs[mid] < begin_time:\n                left = mid\n            else:\n                right = mid\n\n        mid = left if logs[left] >= begin_time else right\n        return len(logs) - mid >= freq\n"
  },
  {
    "path": "lintcode/221_add_two_numbers_ii.py",
    "content": "\"\"\"\nDefinition for singly-linked list.\nclass ListNode:\n    def __init__(self, x):\n        self.val = x\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    def addLists2(self, a, b):\n        \"\"\"\n        :type a: ListNode\n        :type b: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not a and not b:\n            return\n        if not a:\n            return b\n        if not b:\n            return a\n\n        a = self.rev_list(a)\n        b = self.rev_list(b)\n\n        dummy = tail = ListNode(0)\n        carry = 0\n\n        while a and b:\n            carry += a.val + b.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            a = a.next\n            b = b.next\n            tail = tail.next\n\n        while a:\n            carry += a.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            a = a.next\n            tail = tail.next\n\n        while b:\n            carry += b.val\n            tail.next = ListNode(carry % 10)\n            carry //= 10\n            b = b.next\n            tail = tail.next\n\n        if carry:\n            tail.next = ListNode(carry)\n\n        return self.rev_list(dummy.next)\n\n    def rev_list(self, head):\n        pre = nxt = None\n\n        while head:\n            nxt = head.next\n            head.next = pre\n            pre = head\n            head = nxt\n\n        return pre\n"
  },
  {
    "path": "lintcode/231_typeahead.py",
    "content": "class Typeahead:\n    \"\"\"\n    @param: dict: A dictionary of words dict\n    \"\"\"\n    def __init__(self, dict):\n        self.map = {}\n        n = 0\n        for key in dict:\n            n = len(key)\n            for l in range(n):\n                for r in range(l + 1, n + 1):\n                    substr = key[l:r]\n                    if substr not in self.map:\n                        self.map[substr] = [key]\n                    elif self.map[substr][-1] != key:\n                        self.map[substr].append(key)\n\n    \"\"\"\n    @param: str: a string\n    @return: a list of words\n    \"\"\"\n    def search(self, str):\n        if str in self.map:\n            return self.map[str]\n        return []\n\n\n# Solution2\n'''\nThis solution does not meet the demand.\nSince the description said 'return all words that contains the string as a substring.'\n\nBut its a good solution for the auto-completion\n'''\nclass Trie:\n    def __init__(self):\n        self.root = self.new_node()\n\n    def new_node(self):\n        return {\n            'result': [],\n            'children': {}\n        }\n\n    def put(self, key):\n        if not key:\n            return\n        for word in key.split():\n            self._put(word, key)\n\n    def _put(self, word, key):\n        parent = self.root\n        for char in word.lower():\n            if char not in parent['children']:\n                parent['children'][char] = self.new_node()\n            parent = parent['children'][char]\n            parent['result'].append(key)\n\n    def search(self, key):\n        if not key:\n            return []\n        parent = self.root\n        for char in key.lower():\n            if char not in parent['children']:\n                return []\n            parent = parent['children'][char]\n        return parent['result']\n\n    # To support search with 2+ word\n    # def search(self, key):\n    #     if not key:\n    #         return []\n    #     result = []\n    #     for word in key.split():\n    #         result += self._search(word)\n    #     return result\n    # def _search(self, word):\n    #     parent = self.root\n    #     for char in word.lower():\n    #         if char not in parent['children']:\n    #             return []\n    #         parent = parent['children'][char]\n    #     return parent['result']\n\nclass Typeahead:\n    \"\"\"\n    @param: dict: A dictionary of words dict\n    \"\"\"\n    def __init__(self, dict):\n        self.trie = Trie()\n        for word in dict:\n            self.trie.put(word)\n\n    \"\"\"\n    @param: str: a string\n    @return: a list of words\n    \"\"\"\n    def search(self, str):\n        return self.trie.search(str)\n"
  },
  {
    "path": "lintcode/232_tiny_url.py",
    "content": "import random\n\n\nclass TinyUrl:\n    def __init__(self):\n        self.chars = [str(i) for i in range(10)]\n        self.chars.extend(chr(i) for i in range(ord('a'), ord('z') + 1))\n        self.chars.extend(chr(i) for i in range(ord('A'), ord('Z') + 1))\n\n        self.host = 'http://tiny.url/'\n        self.size = 6\n        self.lg2st = {}\n        self.st2lg = {}\n\n    def longToShort(self, url):\n        \"\"\"\n        :type url: str\n        :rtype: str\n        \"\"\"\n        if not url:\n            return 'error'\n        if url in self.lg2st:\n            return self.get_tiny_url(self.lg2st[url])\n\n        key = self.get_hash_key(self.size)\n        while key in self.st2lg:\n            key = self.get_hash_key(self.size)\n\n        self.lg2st[url] = key\n        self.st2lg[key] = url\n        return self.get_tiny_url(key)\n\n    def shortToLong(self, url):\n        \"\"\"\n        :type url: str\n        :rtype: str\n        \"\"\"\n        if not url:\n            return 'error'\n\n        key = url.replace(self.host, '')\n\n        if key in self.st2lg:\n            return self.st2lg[key]\n\n        return 'error'\n\n    def get_tiny_url(self, hash_key):\n        return '{}{}'.format(self.host, hash_key)\n\n    def get_hash_key(self, size):\n        return ''.join(\n            random.choice(self.chars)\n            for _ in range(size)\n        )\n"
  },
  {
    "path": "lintcode/234_webpage_crawler.py",
    "content": "from threading import Thread\nfrom Queue import Queue\nfrom urlparse import urlparse\n\nqueue = Queue()\nresults = {}\n\nclass CrawlerThread(Thread):\n    def run(self):\n        global queue, results\n        while True:\n            url = queue.get()\n            if url not in results \\\n                and urlparse(url).hostname.endswith(\"wikipedia.org\"):\n                results[url] = True\n                urls = HtmlHelper.parseUrls(url)\n                for url in urls:\n                    queue.put(url)\n            queue.task_done()\n\n\n#class HtmlHelper:\n#    @classmethod\n#    def parseUrls(cls, url)\n#       # Get all urls from a webpage of given url.\nclass Solution:\n    # @param {string} url a url of root page\n    # @return {string[]} all urls\n    def crawler(self, url):\n        # Write your code here\n        global queue, results\n        thread_pools = []\n        for i in xrange(10):\n            thread_pools.append(CrawlerThread())\n            thread_pools[i].setDaemon(True)\n            thread_pools[i].start()\n\n        queue.put(url)\n\n        queue.join()\n        rt = []\n        for key, value in results.items():\n            rt.append(key)\n        return rt\n"
  },
  {
    "path": "lintcode/236_swap_bits.py",
    "content": "class Solution:\n    \"\"\"\n    @param: x: An integer\n    @return: An integer\n    \"\"\"\n    def swapOddEvenBits(self, x):\n        \"\"\"\n        0x55555555 == 01010101010101010101010101010101 (2)\n        0xAAAAAAAA == 10101010101010101010101010101010 (2)\n        \"\"\"\n        return ( ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1) )\n"
  },
  {
    "path": "lintcode/242_convert_binary_tree_to_linked_lists_by_depth.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\nDefinition for singly-linked list.\nclass ListNode:\n    def __init__(self, x):\n        self.val = x\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    # @param {TreeNode} root the root of binary tree\n    # @return {ListNode[]} a lists of linked list\n    def binaryTreeToLists(self, root):\n        ans = []\n        if not root:\n            return ans\n\n        queue = [root]\n        while queue:\n            _queue = []\n            dummy = tail = ListNode(-1)\n\n            for node in queue:\n                tail.next = ListNode(node.val)\n                tail = tail.next\n\n                if node.left:\n                    _queue.append(node.left)\n                if node.right:\n                    _queue.append(node.right)\n\n            queue = _queue\n            ans.append(dummy.next)\n\n        return ans\n"
  },
  {
    "path": "lintcode/243_amicable_pair",
    "content": "class Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: all amicable pairs\n    \"\"\"\n    def amicablePair(self, n):\n        ans = []\n        if not n or n < 2:\n            return ans\n\n        for a in range(2, n + 1):\n            b = self.get_factor_sum(a)\n            if a < b <= n and self.get_factor_sum(b) == a:\n                ans.append([a, b])\n\n        return ans\n\n    def get_factor_sum(self, a):\n        \"\"\"\n        if `b` is a factor of `a`\n        => `b` and `a // b` are both factor of `a`\n        => only needs to check til `sqrt(a)`\n        \"\"\"\n        _sum = 1\n        _a = int(math.sqrt(a))\n\n        for b in range(2, _a):\n            if a % b == 0:\n                _sum += b + a // b\n\n        if _a * _a == a:\n            _sum += _a\n\n        return _sum\n"
  },
  {
    "path": "lintcode/245_subtree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: The roots of binary tree A.\n    @param: B: The roots of binary tree B.\n    @return: True if B is a subtree of A, or false.\n    \"\"\"\n    def isSubtree(self, A, B):\n        if not B:\n            # Empty tree is also treated as subtree in Lintcode\n            return True\n        if not A:\n            return False\n\n        return (\n            self.isEqual(A, B) or\n            self.isSubtree(A.left, B) or\n            self.isSubtree(A.right, B)\n        )\n\n    def isEqual(self, A, B):\n        if not A and not B:\n            return True\n        if not A or not B:\n            return False\n\n        return (\n            A.val == B.val and\n            self.isEqual(A.left, B.left) and\n            self.isEqual(A.right, B.right)\n        )\n"
  },
  {
    "path": "lintcode/246_binary_tree_path_sum_ii.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: the root of binary tree\n    @param: target: An integer\n    @return: all valid paths\n    \"\"\"\n    def binaryTreePathSum2(self, root, target):\n        ans = []\n        self.dfs(root, target, ans, [])\n        return ans\n\n    def dfs(self, node, target, ans, path):\n        if not node:\n            return\n\n        path.append(node.val)\n\n        remaining = target\n        for i in range(len(path) - 1, -1, -1):\n            remaining -= path[i]\n            if remaining == 0:\n                ans.append(path[i:])\n\n        self.dfs(node.left, target, ans, path)\n        self.dfs(node.right, target, ans, path)\n\n        path.pop()\n"
  },
  {
    "path": "lintcode/24_lfu_cache.py",
    "content": "\"\"\"\nMain Concept:\n\nDm <-> 2 <-> 3 <-> 8 <-> dm   |<- freq_list (dll)\n       |     |     |\n       a     c     d          |<- cache_list (dll)\n       &           &\n       b           e\n\n1. if cache is updated (set/get)\n    => freq += 1\n    => move to the end of the cache_list in new freq_list\n2. if cache is full\n    => evict the most top-left in cache first,\n       that is `a` in above diagram\n    => add the new cache to the end of the cache_list in freq `0`\n\"\"\"\n\n\nclass LFUCache:\n    def __init__(self, capacity):\n        \"\"\"\n        :type capacity: int\n        \"\"\"\n        self.cap = capacity\n        self.nodes = {}\n        self.D = FreqNode(-1)\n        self.d = FreqNode(-1)\n        self.D.nxt = self.d\n        self.d.pre = self.D\n\n    def get(self, key):\n        \"\"\"\n        :type key: int\n        :rtype: int\n        \"\"\"\n        if key not in self.nodes:\n            return -1\n\n        self._update(key)\n        return self.nodes[key].val\n\n    def set(self, key, val):\n        \"\"\"\n        :type key: int\n        :type val: int\n        :rtype: void\n        \"\"\"\n        if self.cap <= 0:\n            return\n\n        if key in self.nodes:\n            self._update(key, val)\n            return\n\n        while len(self.nodes) >= self.cap:\n            self._evict()\n\n        self._add(key, val)\n\n    def _evict(self):\n        freq_head = self.D.nxt\n        cache_node = freq_head.pop_head()\n        del self.nodes[cache_node.key]\n\n        if freq_head.is_empty():\n            freq_head.unlink()\n\n    def _update(self, key, val=None):\n        cache_node = self.nodes[key]\n\n        if val:\n            cache_node.val = val\n\n        from_freq = cache_node.freq_node\n        to_freq = None\n\n        if from_freq.nxt and from_freq.nxt.freq == from_freq.freq + 1:\n            to_freq = from_freq.nxt\n        else:\n            to_freq = FreqNode(from_freq.freq + 1)\n            from_freq.after(to_freq)\n\n        cache_node.unlink()\n        to_freq.append_tail(cache_node)\n\n        if from_freq.is_empty():\n            from_freq.unlink()\n\n    def _add(self, key, val):\n        cache_node = CacheNode(key, val)\n        self.nodes[key] = cache_node\n\n        freq_head = self.D.nxt\n        if freq_head and freq_head.freq == 0:\n            freq_head.append_tail(cache_node)\n            return\n\n        freq_head = FreqNode(0)\n        freq_head.append_tail(cache_node)\n        self.D.after(freq_head)\n\n\nclass CacheNode:\n    def __init__(self, key, val=None, freq_node=None, pre=None, nxt=None):\n        self.key = key\n        self.val = val\n        self.freq_node = freq_node\n        self.pre = pre\n        self.nxt = nxt\n\n    # to change self in cache nodes\n    def unlink(self):\n        self.pre.nxt = self.nxt\n        self.nxt.pre = self.pre\n        self.freq_node = self.pre = self.nxt = None\n\n\nclass FreqNode:\n    def __init__(self, freq, pre=None, nxt=None):\n        self.freq = freq\n        self.pre = pre\n        self.nxt = nxt\n        self.D = CacheNode(-1)\n        self.d = CacheNode(-1)\n        self.D.nxt = self.d\n        self.d.pre = self.D\n\n    # to change self in freq nodes\n    def unlink(self):\n        self.pre.nxt = self.nxt\n        self.nxt.pre = self.pre\n        self.pre = self.nxt = self.D = self.d = None\n\n    # to change self in freq nodes\n    def after(self, freq_node):\n        freq_node.pre = self\n        freq_node.nxt = self.nxt\n        self.nxt.pre = freq_node\n        self.nxt = freq_node\n\n    # to manage cache nodes\n    def is_empty(self):\n        return self.D.nxt is self.d\n\n    # to manage cache nodes\n    def pop_head(self):\n        if self.is_empty():\n            return\n\n        head = self.D.nxt\n        head.unlink()\n        return head\n\n    # to manage cache nodes\n    def append_tail(self, cache_node):\n        cache_node.freq_node = self\n        cache_node.pre = self.d.pre\n        cache_node.nxt = self.d\n        self.d.pre.nxt = cache_node\n        self.d.pre = cache_node\n"
  },
  {
    "path": "lintcode/254_drop_eggs.py",
    "content": "\"\"\"\nREF: http://blog.csdn.net/shaya118/article/details/40823225\n\nMain Concept:\n\nassuming the minimum times to drop is `x`\naccording to REF, the relation of `x` is below\n\n         |\n         | x\n    |....|\n. | |....|\n   x + 1\n\n0 + 1 + 2 + ... + x\n=> x(x + 1) / 2 >= n\n\"\"\"\n\n\n\"\"\"\ncumulative the sum of the triangle\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: The sum of a and b\n    \"\"\"\n    def dropEggs(self, n):\n        if n <= 0:\n            return 0\n\n        _sum = 0\n        for i in range(n):\n            _sum += i\n            if _sum >= n:\n                return i\n\n        return n\n\n\n\"\"\"\noptimized: cumulative the sum of the triangle\n\nx(x + 1) / 2 >= n\n=> sqrt(x(x + 1)) >= sqrt(2n)\n=> sqrt(x(x + 1)) >= sqrt(x^2) == x >= sqrt(2n)\n\nso `x` can start from `sqrt(2n)`\n\"\"\"\nfrom math import sqrt\n\n\nclass Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: The sum of a and b\n    \"\"\"\n    def dropEggs(self, n):\n        if n <= 0:\n            return 0\n\n        x = int(sqrt(2 * n))\n        while x * (x + 1) // 2 < n:\n            x += 1\n\n        return x\n"
  },
  {
    "path": "lintcode/272_climbing_stairs_ii.py",
    "content": "\"\"\"\ndp: space optimized by rolling array\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: An integer\n    \"\"\"\n    def climbStairs2(self, n):\n        if not n or n <= 1:\n            return 1\n        if n == 2:\n            return 2\n\n        a, b, c = 1, 1, 2\n        for i in range(3, n + 1):\n            a, b, c = b, c, a + b + c\n\n        return c\n\n\n\"\"\"\ndp\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: n: An integer\n    @return: An integer\n    \"\"\"\n    def climbStairs2(self, n):\n        if not n or n <= 1:\n            return 1\n        if n == 2:\n            return 2\n\n        dp = [0] * (n + 1)\n        dp[0] = dp[1] = 1\n        dp[2] = 2\n\n        for i in range(3, n + 1):\n            dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/28_search_a_2d_matrix.py",
    "content": "class Solution:\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: list[list[int]]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return False\n\n        m, n = len(matrix), len(matrix[0])\n        left, right = 0, m * n - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            x = mid // n\n            y = mid % n\n\n            if matrix[x][y] < target:\n                left = mid\n            elif matrix[x][y] > target:\n                right = mid\n            else:\n                return True\n\n        return any(\n            matrix[mid // n][mid % n] == target\n            for mid in (left, right)\n        )\n"
  },
  {
    "path": "lintcode/29_interleaving_string.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: A string\n    @param: B: A string\n    @param: C: A string\n    @return: Determine whether C is formed by interleaving of A and B\n    \"\"\"\n    def isInterleave(self, A, B, C):\n        if A is None or B is None or C is None:\n            return False\n\n        if A is '' and B is '' and C is '':\n            return True\n\n        a, b, c = len(A), len(B), len(C)\n        if c != a + b:\n            return False\n\n        \"\"\"\n        `dp[i][j]` means the substr end at `C[i + j - 1]`\n        is mixed by the substr end at `A[i - 1]`\n        and the substr end at `B[j - 1]`\n        \"\"\"\n        dp = [[False] * (b + 1) for _ in range(2)]\n\n        prev = curr = 0\n        dp[curr][0] = True\n\n        for j in range(1, b + 1):\n            \"\"\"\n            dp[0][j] = (dp[0][j - 1] and B[j - 1] == C[j - 1])\n            \"\"\"\n            if not dp[curr][j - 1]:\n                break\n\n            if B[j - 1] == C[j - 1]:\n                dp[curr][j] = True\n\n        for i in range(1, a + 1):\n            prev = curr\n            curr = 1 - curr\n\n            \"\"\"\n            dp[i][0] = (dp[i - 1][0] and A[i - 1] == C[i - 1])\n            \"\"\"\n            if dp[prev][0] and A[i - 1] == C[i - 1]:\n                dp[curr][0] = True\n\n            for j in range(1, b + 1):\n                dp[curr][j] = False\n\n                if dp[prev][j] and A[i - 1] == C[i + j - 1]:\n                    dp[curr][j] = True\n                    continue\n\n                if dp[curr][j - 1] and B[j - 1] == C[i + j - 1]:\n                    dp[curr][j] = True\n\n        return dp[curr][b]\n"
  },
  {
    "path": "lintcode/30_insert_interval.py",
    "content": "\"\"\"\nMain Concept:\n1. iterate from end, find the position to insert new one\n2. append new one to `intvs`\n3. iterate from end, and swap `intvs[i]` and `intvs[i - 1]`\n   til meet the position found in (1)\n4. iterate from start, do merge intv\n\n\nDefinition of Interval.\nclass Interval(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n\"\"\"\n\n\nclass Solution:\n    def insert(self, intvs, intv):\n        \"\"\"\n        :type intvs: list[Interval]\n        :type intv: Interval\n        :rtype: list[Interval]\n        \"\"\"\n        if not intvs and not intv:\n            return []\n        if not intvs:\n            return [intv]\n        if not intv:\n            return intvs\n\n        ans = []\n        index = len(intvs)\n\n        for i in range(len(intvs) - 1, -1, -1):\n            if intvs[i].start <= intv.start:\n                break\n            index -= 1\n\n        intvs.append(intv)\n        for i in range(len(intvs) - 1, index, -1):\n            intvs[i], intvs[i - 1] = intvs[i - 1], intvs[i]\n\n        for i in range(len(intvs)):  # since there is one more child in intvs\n            if ans and intvs[i].start <= ans[-1].end:\n                ans[-1].end = max(ans[-1].end, intvs[i].end)\n            else:\n                ans.append(intvs[i])\n\n        return ans\n"
  },
  {
    "path": "lintcode/31_partition_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: The integer array you should partition\n    @param: k: An integer\n    @return: The index after partition\n    \"\"\"\n    def partitionArray(self, A, k):\n        if not A:\n            return 0\n\n        left, right = 0, len(A) - 1\n\n        while left <= right:\n            while left <= right and A[left] < k:\n                left += 1\n            while left <= right and A[right] >= k:\n                right -= 1\n\n            if left <= right:\n                A[left], A[right] = A[right], A[left]\n                left += 1\n                right -= 1\n\n        return left\n"
  },
  {
    "path": "lintcode/32_minimum_window_substring.py",
    "content": "class Solution:\n    def minWindow(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        if not s or not t:\n            return ''\n\n        F = {}\n        for c in t:\n            F[c] = F.get(c, 0) + 1\n\n        n, cnt = len(s), len(F)\n        start = size = INFINITY = float('inf')\n        left = right = 0\n\n        while right < n:\n            if s[right] in F:\n                F[s[right]] -= 1\n                if F[s[right]] == 0:\n                    cnt -= 1\n\n            right += 1\n\n            while cnt == 0:\n                if s[left] in F:\n                    F[s[left]] += 1\n                    if F[s[left]] == 1:\n                        cnt += 1\n\n                if right - left < size:\n                    size = right - left\n                    start = left\n\n                left += 1\n\n        return s[start:start + size] if size < INFINITY else ''\n"
  },
  {
    "path": "lintcode/35_reverse_linked_list.py",
    "content": "\"\"\"\nDefinition of ListNode\n\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: n\n    @return: The new head of reversed linked list.\n    \"\"\"\n    def reverse(self, head):\n        \"\"\"\n        example: 1->2->3\n\n        r0:\n            head: 1\n            pre: None\n            nxt: None\n        r1:\n            head: 2\n            pre: 1\n            nxt: 2->3\n        r2:\n            head: 3\n            pre: 2->1\n            nxt: 3\n        r3:\n            head: None\n            pre: 3->2->1\n            nxt: None\n        \"\"\"\n        pre = nxt = None\n\n        while head:\n            nxt = head.next  # save the remaining children\n            head.next = pre  # break the link\n            pre = head       # save the new head\n            head = nxt       # pointer the old head\n\n        return pre\n"
  },
  {
    "path": "lintcode/360_sliding_window_median.py",
    "content": "import heapq\n\n\nclass HashHeapqWithLazy:\n    def __init__(self):\n        self.__heap = []\n        self.__deleted = {}\n        self.__size = 0\n\n    def __len__(self):\n        return self.__size\n\n    def __bool__(self):\n        return self.__size > 0\n\n    def push(self, val):\n        heapq.heappush(self.__heap, val)\n        self.__size += 1\n\n    def pop(self):\n        if self._is_empty():\n            return\n\n        self.__size -= 1\n        return heapq.heappop(self.__heap)\n\n    def remove(self, val):\n        if self._is_empty():\n            return\n\n        self.__size -= 1\n        self.__deleted[val] = self.__deleted.get(val, 0) + 1\n\n    def top(self):\n        if self._is_empty():\n            return\n\n        return self.__heap[0]\n\n    def _is_empty(self):\n        while self.__heap and self.__deleted.get(self.__heap[0]):\n            val = heapq.heappop(self.__heap)\n            self.__deleted[val] -= 1\n\n        return self.__size == 0\n\n\nclass Solution:\n    def medianSlidingWindow(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: List[float]\n        \"\"\"\n        ans = []\n\n        if not nums or k <= 0 or len(nums) < k:\n            return ans\n\n        self.minheap = HashHeapqWithLazy()\n        self.maxheap = HashHeapqWithLazy()\n\n        for i in range(len(nums)):\n            # remove nums[i - k]\n            if i >= k:\n                if self.minheap and nums[i - k] >= self.minheap.top():\n                    self.minheap.remove(nums[i - k])\n                else:\n                    self.maxheap.remove(-1 * nums[i - k])\n\n            # add nums[i]\n            if self.minheap and nums[i] >= self.minheap.top():\n                self.minheap.push(nums[i])\n            else:\n                self.maxheap.push(-1 * nums[i])\n\n            # get median\n            if i >= k - 1:\n                ans.append(self.get_median())\n\n        return ans\n\n    def get_median(self):\n        if not self.maxheap and not self.minheap:\n            return 0\n\n        while len(self.maxheap) > len(self.minheap) + 1:\n            self.minheap.push(-1 * self.maxheap.pop())\n\n        while len(self.minheap) > len(self.maxheap):\n            self.maxheap.push(-1 * self.minheap.pop())\n\n        return -1 * self.maxheap.top()\n"
  },
  {
    "path": "lintcode/362_sliding_window_maximum.py",
    "content": "from heapq import heappush, heappop\n\n\nclass HashHeapq:\n    def __init__(self):\n        self.heap = []\n        self.deleted = {}\n\n    def push(self, val):\n        heappush(self.heap, val)\n\n    def pop(self):\n        if self.is_empty():\n            return\n        heappop(self.heap)\n\n    def remove(self, val):\n        if self.is_empty():\n            return\n        self.deleted[val] = self.deleted.get(val, 0) + 1\n\n    def top(self):\n        if self.is_empty():\n            return\n        return self.heap[0]\n\n    def is_empty(self):\n        while self.heap and self.deleted.get(self.heap[0]):\n            self.deleted[self.heap[0]] -= 1\n            heappop(self.heap)\n        return not self.heap\n\n\nclass Solution:\n    def maxSlidingWindow(self, A, k):\n        \"\"\"\n        :type A: List[int]\n        :type k: int\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n        if not A:\n            return ans\n\n        heap = HashHeapq()\n\n        for i in range(len(A)):\n            heap.push(-A[i])\n            if i >= k - 1:\n                ans.append(-heap.top())\n                heap.remove(-A[i - k + 1])\n\n        return ans\n\n\n\"\"\"\nFailed Solution\nSince its a O(n*k) solution\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @param: k: An integer\n    @return: The maximum number inside the window at each moving\n    \"\"\"\n    def maxSlidingWindow(self, A, k):\n        ans = []\n        if not A or len(A) < 1:\n            return ans\n        for r in range(len(A)):\n            if r >= k - 1:\n                ans.append(max(A[r - k + 1 : r + 1]))\n        return ans\n"
  },
  {
    "path": "lintcode/363_trapping_rain_water.py",
    "content": "class Solution:\n    \"\"\"\n    @param: heights: a list of integers\n    @return: a integer\n    \"\"\"\n    def trapRainWater(self, heights):\n        if not heights:\n            return 0\n        # mx_l: max height for index `l`\n        # mx_r: max height for index `r`\n        mx_l = mx_r = ans = 0\n        l, r = 0, len(heights) - 1\n        while l < r:\n            # To find the max height in heights\n            if heights[l] < heights[r]:\n                mx_l = max(mx_l, heights[l])\n                ans += mx_l - heights[l]\n                l += 1\n            else:\n                mx_r = max(mx_r, heights[r])\n                ans += mx_r - heights[r]\n                r -= 1\n        return ans\n"
  },
  {
    "path": "lintcode/364_trapping_rain_water_ii.py",
    "content": "from heapq import heappush, heappop\n\nclass Solution:\n    \"\"\"\n    @param: heights: a matrix of integers\n    @return: an integer\n    \"\"\"\n    def trapRainWater(self, heights):\n        if not heights:\n            return 0\n        m, n = len(heights), len(heights[0])\n        dx, dy = [1, -1, 0, 0], [0, 0, 1, -1]\n        ans = bound = x = y = i = 0\n        bounds = []\n        visited = [[0 for _ in range(n)] for _ in range(m)]\n\n        # Put the cells on the matrix boundaries into `bounds`\n        for i in range(m):\n            heappush(bounds, (heights[i][0], i, 0))\n            visited[i][0] = 1\n            heappush(bounds, (heights[i][n - 1], i, n - 1))\n            visited[i][n - 1] = 1\n        for i in range(1, n - 1):\n            heappush(bounds, (heights[0][i], 0, i))\n            visited[0][i] = 1\n            heappush(bounds, (heights[m - 1][i], m - 1, i))\n            visited[m - 1][i] = 1\n\n        while bounds:\n            # Find the min bound of any current boundary\n            bound, x, y = heappop(bounds)\n            # To keep the water in, keep finding the boundary\n            for i in range(4):\n                _x = x + dx[i]\n                _y = y + dy[i]\n                if 0 <= _x < m and 0 <= _y < n and not visited[_x][_y]:\n                    visited[_x][_y] = 1\n                    # Choosing the boundary of current cell\n                    # if its lower than the bound outside\n                    # than this cell will store water\n                    # otherwise this cell will become the new boundary\n                    _bound = max(bound, heights[_x][_y])\n                    heappush(bounds, (_bound, _x, _y))\n                    if _bound > heights[_x][_y]:\n                        ans += _bound - heights[_x][_y]\n        return ans\n"
  },
  {
    "path": "lintcode/368_expression_evaluation.py",
    "content": "\"\"\"\nREF: [Reverse Polish Notation](https://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95)\nREF: [Direct Algebraic Logic to Reverse Polish Notation](http://blog.csdn.net/sgbfblog/article/details/8001651)\n\"\"\"\n\n\nclass Solution:\n    P = {\n        '+': 1,\n        '-': 1,\n        '*': 2,\n        '/': 2,\n    }\n\n    \"\"\"\n    @param: E: a list of strings\n    @return: an integer\n    \"\"\"\n    def evaluateExpression(self, E):\n        if not E:\n            return 0\n\n        E = self.dal2rpn(E)\n\n        \"\"\"\n        for cases like `[\"(\",\"(\",\"(\",\"(\",\"(\",\")\",\")\",\")\",\")\",\")\"]`\n        \"\"\"\n        if not E:\n            return 0\n\n        return self.eval_rpn(E)\n\n    def dal2rpn(self, E):\n        \"\"\"\n        `stack` to save operators and brackets temply\n        `res` is the RPN of `E`, to save digits and operators\n        \"\"\"\n        stack, res = [], []\n\n        for char in E:\n            if char.isdigit():\n                \"\"\"\n                if its digit\n                then directly output\n                \"\"\"\n                res.append(char)\n                continue\n\n            if char in self.P:\n                \"\"\"\n                if `stack` is not empty\n                and `stack[-1]` is an operator\n                and its priority is higher or same ('*' == '/' > '+' == '-')\n                then pop and output\n                \"\"\"\n                while (stack and stack[-1] in self.P and\n                       self.P[stack[-1]] >= self.P[char]):\n                    res.append(stack.pop())\n                stack.append(char)\n            elif char == '(':\n                stack.append(char)\n            elif char == ')':\n                \"\"\"\n                if its ')'\n                then continue to pop and output\n                until meet '('\n                \"\"\"\n                while stack and stack[-1] != '(':\n                    res.append(stack.pop())\n                stack.pop()  # evict '('\n\n        \"\"\"\n        output the remaining in `stack`\n        \"\"\"\n        while stack:\n            res.append(stack.pop())\n\n        return res\n\n    def eval_rpn(self, E):\n        stack = []\n        for char in E:\n            if char.isdigit():\n                \"\"\"\n                if its digit\n                then temply save in `stack`\n                \"\"\"\n                stack.append(int(char))\n                continue\n\n            \"\"\"\n            the first poped one is base,\n            otherwise there is error occurred when '/' and '-'\n            \"\"\"\n            b = stack.pop()\n            a = stack.pop()\n\n            if char == '+':\n                stack.append(a + b)\n            elif char == '-':\n                stack.append(a - b)\n            elif char == '*':\n                stack.append(a * b)\n            elif char == '/':\n                stack.append(a // b)\n\n        return stack[0]\n"
  },
  {
    "path": "lintcode/36_reverse_linked_list_ii.py",
    "content": "\"\"\"\nDefinition of ListNode\n\nclass ListNode(object):\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: ListNode head is the head of the linked list\n    @param: m: An integer\n    @param: n: An integer\n    @return: The head of the reversed ListNode\n    \"\"\"\n    def reverseBetween(self, head, m, n):\n        if not head:\n            return\n\n        \"\"\"\n        to get to `n`th node from `m`th node needs `n - m` operations\n        \"\"\"\n        n -= m\n\n        \"\"\"\n        `A` will stay at `m-1`th node\n        \"\"\"\n        A = dummy = ListNode(-1, head)\n        while m > 1:\n            m -= 1\n            A = A.next\n\n        \"\"\"\n        `B` will stay at `n+1`th node\n        `cur` stay at (`m`th -> `n`th) node\n        \"\"\"\n        B = cur = A.next\n        pre = nxt = None\n        while n >= 0:\n            n -= 1\n            nxt = B.next\n            B.next = pre\n            pre = B\n            B = nxt\n\n        A.next = pre\n        cur.next = B\n\n        return dummy.next\n"
  },
  {
    "path": "lintcode/376_binary_tree_path_sum.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: the root of binary tree\n    @param: target: An integer\n    @return: all valid paths\n    \"\"\"\n    def binaryTreePathSum(self, root, target):\n        ans = []\n        self.dfs(root, target, ans, [])\n        return ans\n\n    def dfs(self, node, remaining, ans, path):\n        if not node:\n            return\n\n        path.append(node.val)\n\n        remaining -= node.val\n        if remaining == 0 and not node.left and not node.right:\n            ans.append(path[:])\n\n        self.dfs(node.left, remaining, ans, path)\n        self.dfs(node.right, remaining, ans, path)\n\n        path.pop()\n"
  },
  {
    "path": "lintcode/378_convert_binary_search_tree_to_doubly_linked_list.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\nDefinition of Doubly-ListNode\nclass DoublyListNode(object):\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = self.prev = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: The root of tree\n    @return: the head of doubly list node\n    \"\"\"\n    def bstToDoublyList(self, root):\n        if not root:\n            return\n\n        dummy = tail = DoublyListNode(-1)\n        stack = []\n        node = root\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n\n            _node = DoublyListNode(node.val)\n            _node.prev = tail\n            tail.next = _node\n            tail = tail.next\n\n            node = node.right\n\n        return dummy.next\n"
  },
  {
    "path": "lintcode/382_triangle_count.py",
    "content": "class Solution:\n    \"\"\"\n    @param: S: A list of integers\n    @return: An integer\n    \"\"\"\n    def triangleCount(self, S):\n        ans = 0\n        if not S or len(S) < 3:\n            return ans\n\n        n = len(S)\n        S.sort()\n\n        \"\"\"\n        just like two sum\n        `c` is the target\n        \"\"\"\n        for c in range(n - 1, 1, -1):\n            a = 0\n            b = c - 1\n            while a < b:\n                if S[a] + S[b] > S[c]:\n                    ans += b - a\n                    b -= 1\n                else:\n                    a += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/384_longest_substring_without_repeating_characters.py",
    "content": "import collections\n\n\nclass Solution:\n    def lengthOfLongestSubstring(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not s:\n            return ans\n\n        freqs = collections.defaultdict(int)\n        i = rep = 0\n\n        for j in range(len(s)):\n            if freqs[s[j]] == 1:\n                rep += 1\n            freqs[s[j]] += 1\n\n            while rep > 0:\n                freqs[s[i]] -= 1\n                if freqs[s[i]] == 1:\n                    rep -= 1\n\n                i += 1\n\n            ans = max(ans, j - i + 1)\n\n        return ans\n"
  },
  {
    "path": "lintcode/386_longest_substring_with_at_most_k_distinct_characters.py",
    "content": "import collections\n\n\nclass Solution:\n    def lengthOfLongestSubstringKDistinct(self, s, k):\n        \"\"\"\n        :type s: str\n        :type k: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not s or not k:\n            return ans\n\n        freq = collections.defaultdict(int)\n        n = len(s)\n        left = right = cnt = 0\n\n        while right < n:\n            freq[s[right]] += 1\n            if freq[s[right]] == 1:\n                cnt += 1\n\n            right += 1\n\n            while cnt > k:\n                freq[s[left]] -= 1\n                if freq[s[left]] == 0:\n                    cnt -= 1\n\n                left += 1\n\n            if right - left > ans:\n                ans = right - left\n\n        return ans\n"
  },
  {
    "path": "lintcode/38_search_a_2d_matrix_ii.py",
    "content": "\"\"\"\nHeap\n\"\"\"\nimport heapq\n\n\nclass Solution:\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: list[list[int]]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not matrix or not matrix[0]:\n            return ans\n\n        heap = []\n        m, n = len(matrix), len(matrix[0])\n\n        for i in range(m):\n            heapq.heappush(heap, (matrix[i][0], i, 0))\n\n        while heap and heap[0][0] <= target:\n            num, x, y = heapq.heappop(heap)\n\n            if num == target:\n                ans += 1\n\n            y += 1\n            if y < n:\n                heapq.heappush(heap, (matrix[x][y], x, y))\n\n        return ans\n\n\n\"\"\"\nIteration\n\nstart from bottom-left of matrix\n\nif `G[x][y] > target`:\n    need to check `x - 1`\n    all cells before `y - 1` are confirmed in last iteration\nelse:\n    all cells before `x + 1` are confirmed in last iteration\n    need to check `y + 1`\n\"\"\"\nclass Solution:\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: list[list[int]]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not matrix or not matrix[0]:\n            return ans\n\n        m, n = len(matrix), len(matrix[0])\n        x, y = m - 1, 0\n\n        while x >= 0 and y < n:\n            if matrix[x][y] < target:\n                y += 1\n            elif matrix[x][y] > target:\n                x -= 1\n            else:\n                ans += 1\n                x -= 1\n                y += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/390_find_peak_element_ii.py",
    "content": "\"\"\"\nTest Case\n\n[[  1,  2,  3,  6,  5 ]\n,[ 16, 41, 23, 22,  6 ]\n,[ 15, 17, 24, 21,  7 ]\n,[ 14, 18, 19, 20, 10 ]\n,[ 13, 14, 11, 10,  9 ]]\n\n[[  1,  3,  2 ]\n,[  4,  6,  5 ]\n,[  7,  9,  8 ]\n,[ 13, 15, 14 ]\n,[ 10, 12, 11 ]]\n\"\"\"\n\nclass Solution:\n    NULL_POS = [-1, -1]\n    dx = [1, -1, 0, 0]\n    dy = [0, 0, 1, -1]\n\n    \"\"\"\n    @param: A: An integer matrix\n    @return: The index of the peak\n    \"\"\"\n    \"\"\"\n    step0/ given matrix and its size is 6*6\n    step1/ chosen the mid_col is 3, the max_value on that col at (2, 3),\n           and the value at (2, 2) great than it\n    step2/ chosen the mid_row is 2, the max_value in the segment[0:3] on that row at (2, 1),\n           and the value at (3, 1) great than it\n    step3/ keep slicing row or col if its range is more wide\n    ...\n    step-1/ find a square and check the vertices\n    \"\"\"\n    def findPeakII(self, A):\n        if not A:\n            return self.NULL_POS\n\n        self.m, self.n = len(A), len(A[0])\n        left, col, right = 0, 0, self.n - 1\n        up, row, down = 0, 0, self.m - 1\n\n        while left + 1 < right or up + 1 < down:\n            if down - up > right - left:\n                row = up + (down - up) // 2\n                col = self.findRowMax(A, row, left, right)\n                if self.isPeak(A, row, col):\n                    return [row, col]\n                if A[row][col] < A[row-1][col]:\n                    down = row\n                else:\n                    up = row\n            else:\n                col = left + (right - left) // 2\n                row = self.findColMax(A, col, up, down)\n                if self.isPeak(A, row, col):\n                    return [row, col]\n                if A[row][col] < A[row][col-1]:\n                    right = col\n                else:\n                    left = col\n        for r in [up, down]:\n            for c in [left, right]:\n                if self.isPeak(A, r, c):\n                    return [r, c]\n        return self.NULL_POS\n\n    # given col index, return the row index of the max value on that col\n    def findColMax(self, A, col, up, down):\n        row = 0\n        for r in range(up, down + 1):\n            if A[row][col] < A[r][col]:\n                row = r\n        return row\n\n    # given row index, return the col index of the max value on that row\n    def findRowMax(self, A, row, left, right):\n        col = 0\n        for c in range(left, right + 1):\n            if A[row][col] < A[row][c]:\n                col = c\n        return col\n\n    def isPeak(self, A, row, col):\n        _r = _c = 0\n        for i in range(4):\n            _r = row + self.dx[i]\n            _c = col + self.dy[i]\n            if 0 <= _r < self.m \\\n                    and 0 <= _c < self.n \\\n                    and A[row][col] < A[_r][_c]:\n                return 0\n        return 1\n"
  },
  {
    "path": "lintcode/391_number_of_airplanes_in_the_sky.py",
    "content": "\"\"\"\nDefinition of Interval.\nclass Interval(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: airplanes: An interval array\n    @return: Count of airplanes are in the sky.\n    \"\"\"\n    def countOfAirplanes(self, airplanes):\n        ans = 0\n        if not airplanes:\n            return ans\n        cnt = 0\n        timeline = []\n        for interval in airplanes:\n            timeline.append((interval.start, 1))\n            timeline.append((interval.end, 0))\n        timeline.sort()\n        for _, in_sky in timeline:\n            if in_sky:\n                cnt += 1\n            else:\n                cnt -= 1\n            ans = max(ans, cnt)\n        return ans\n"
  },
  {
    "path": "lintcode/392_house_robber.py",
    "content": "\"\"\"\nto borrow the idea of `./lintcode/515_paint_house.py`\na house can be at one of two status: steal or not\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An array of non-negative integers\n    @return: The maximum amount of money you can rob tonight\n    \"\"\"\n    def houseRobber(self, A):\n        if not A:\n            return 0\n\n        n = len(A)\n        prev = curr = 0\n        dp = [[0] * 2 for _ in range(2)]\n        dp[0][1] = A[0]\n\n        for i in range(1, n):\n            prev = curr # (i - 1) % 2\n            curr = i % 2\n\n            dp[curr][0] = max(dp[prev])\n            dp[curr][1] = dp[prev][0] + A[i]\n\n        return max(dp[curr])\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of non-negative integers\n    @return: The maximum amount of money you can rob tonight\n    \"\"\"\n    def houseRobber(self, A):\n        if not A:\n            return 0\n        if len(A) == 1:\n            return A[0]\n\n        n = len(A)\n\n        # `dp[i]`: the maximum amount of money we can get until house `i`\n        dp = [0] * 3\n\n        dp[0] = A[0]\n        dp[1] = max(A[0], A[1])\n\n        prev2, prev1, curr = 0, 0, 1\n        for i in range(2, n):\n            prev2, prev1 = prev1, curr\n            curr = i % 3\n\n            \"\"\"\n            if house `i` was stolen, we can't steal house `i - 1`,\n            the amount is `dp[i - 2] + A[i]`\n            if house `i` is not stolen, we can steal house `i - 1`,\n            but we lose the `A[i]`,\n            the amount is `dp[i - 1] + 0`\n            \"\"\"\n            dp[curr] = max(dp[prev1], dp[prev2] + A[i])\n\n        return dp[curr]\n\n\nclass Solution:\n    def houseRobber(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        if not A:\n            return 0\n\n        n = len(A)\n        dp = [0] * (n + 1)\n        dp[1] = A[0]\n\n        for i in range(2, n + 1):\n            dp[i] = max(\n                dp[i - 2] + A[i - 1],\n                dp[i - 1]\n            )\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/393_best_time_to_buy_and_sell_stock_iv.py",
    "content": "class Solution:\n    \"\"\"\n    @param: K: An integer\n    @param: P: An integer array\n    @return: Maximum profit\n    \"\"\"\n    def maxProfit(self, K, P):\n        if not K or not P:\n            return 0\n\n        n = len(P)\n\n        \"\"\"\n        if `K >= n`, this problem is just\n        `./lintcode/150_best_time_to_buy_and_sell_stock_ii.py`\n        so we dont need to use `dp`, since it lead to overflow\n        \"\"\"\n        if K >= n:\n            profit = 0\n            for i in range(1, n):\n                if P[i] > P[i - 1]:\n                    profit += P[i] - P[i - 1]\n            return profit\n\n        \"\"\"\n        the main concept is in\n        `./lintcode/151_best_time_to_buy_and_sell_stock_iii.py`\n        \"\"\"\n        STAGE = 2 * K + 1\n        dp = [[0] * STAGE for _ in range(2)]\n\n        i = j = prev = curr = profit = 0\n        for i in range(1, n):\n            prev = curr\n            curr = 1 - prev\n            profit = P[i] - P[i - 1]\n            for j in range(1, STAGE, 2):\n                dp[curr][j] = max(dp[prev][j] + profit, dp[prev][j - 1])\n            for j in range(2, STAGE, 2):\n                dp[curr][j] = max(dp[prev][j], dp[prev][j - 1] + profit)\n\n        return max(dp[curr])\n"
  },
  {
    "path": "lintcode/394_coins_in_a_line.py",
    "content": "\"\"\"\nThere are n coins in a line.\nTwo players take turns to take one or two coins from right side\nuntil there are no more coins left.\nThe player who take the last coin wins.\nCould you please decide the first play will win or lose?\n\n\n`dp[i]` means first play will win if left `i` stones in line\n\n`dp[i]` =\nTrue,  if dp[i - 1] == False and dp[i - 2] == False\nTrue,  if dp[i - 1] == True  and dp[i - 2] == False\nTrue,  if dp[i - 1] == False and dp[i - 2] == True\n\nFalse, if dp[i - 1] == True  and dp[i - 2] == True\n=> dp[i - 1] == False or dp[i - 2] == False\n\nthe meaning is if the p2 is possible to lose\nwhen stones == i - 1 or i - 2\n=> p1 will win\n\"\"\"\n\n\nclass Solution:\n    def firstWillWin(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        if not n:\n            return False\n        if n < 3:\n            return True\n\n        dp = [False] * n\n        dp[0] = dp[1] = True\n\n        for i in range(2, n):\n            if (\n                dp[i - 1] is False or\n                dp[i - 2] is False\n            ):\n                dp[i] = True\n\n        return dp[n - 1]\n"
  },
  {
    "path": "lintcode/395_coins_in_a_line_ii.py",
    "content": "\"\"\"\nThere are n coins with different value in a line.\nTwo players take turns to take one or two coins from left side\nuntil there are no more coins left.\nThe player who take the coins with the most value wins.\nCould you please decide the first player will win or lose?\n\n\n`dp[i]` means the p1 earned values if game start from `i`\n\ncase 1: if p2 will take the `i + 1`\n=> values[i] - dp[i + 1]\ncase 2: if p2 will take the `i + 2`\n=> values[i] + values[i + 1] - dp[i + 2]\n\"\"\"\n\n\nclass Solution:\n    def firstWillWin(self, values):\n        \"\"\"\n        :type values: list[int]\n        :rtype: bool\n        \"\"\"\n        if not values:\n            return False\n\n        n = len(values)\n\n        if n < 3:\n            return True\n\n        dp = [False] * n\n        dp[-1] = values[-1]\n        dp[-2] = values[-1] + values[-2]\n\n        for i in range(n - 3, -1, -1):\n            dp[i] = max((\n                values[i] - dp[i + 1],\n                values[i] + values[i + 1] - dp[i + 2],\n            ))\n\n        return dp[0] >= 0\n"
  },
  {
    "path": "lintcode/396_coins_in_a_line_iii.py",
    "content": "\"\"\"\nThere are n coins in a line.\nTwo players take turns to take a coin from one of the ends of the line\nuntil there are no more coins left.\nThe player with the larger amount of money wins.\nCould you please decide the first player will win or lose?\n\n\n`dp[i][j]` means the maximum value when\nthe current player chosen from [i, j] in `values`\n\nrecurring from the end of the game to start\nso init with `dp[i][i]`\n\ni   i+1     j-1  j\nc1  c2  c3  c4  c5\n\nthere are two cases:\n    1. if the current player chosen `values[i]`, then\n       the cost is `dp[i + 1][j]`\n    2. if the current player chosen `values[j]`, then\n       the cost is `dp[i][j - 1]`\n\nchosen the maximum\n\"\"\"\n\n\nclass Solution:\n    def firstWillWin(self, values):\n        \"\"\"\n        :type values: list[int]\n        :rtype: bool\n        \"\"\"\n        if not values:\n            return False\n\n        n = len(values)\n\n        if n < 2:\n            return True\n\n        dp = [[0] * n for _ in range(n)]\n\n        for i in range(n):\n            dp[i][i] = values[i]\n\n        for i in range(n - 1 - 1, -1, -1):\n            for j in range(i + 1, n):\n                dp[i][j] = max((\n                    values[i] - dp[i + 1][j],\n                    values[j] - dp[i][j - 1],\n                ))\n\n        return dp[0][n - 1] >= 0\n"
  },
  {
    "path": "lintcode/397_longest_increasing_continuous_subsequence.py",
    "content": "\"\"\"\nDP + print path\nremove the single line comment to see the path in result\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An array of Integer\n    @return: an integer\n    \"\"\"\n    def longestIncreasingContinuousSubsequence(self, A):\n        if not A:\n            return 0\n\n        size = self.get_lics_size(A)\n        A.reverse()\n        _size = self.get_lics_size(A)\n\n        return max(size, _size)\n\n    def get_lics_size(self, A):\n        ans = 0\n        n = len(A)\n\n        \"\"\"\n        `dp[i]` means the size of LICS ended at `A[i]`\n        note that there is size, so init with `1`\n        \"\"\"\n        dp = [1] * n\n\n        # pi = [-1] * n\n        # end_at = -1\n\n        for i in range(n):\n            if i > 0 and A[i] > A[i - 1]:\n                dp[i] = dp[i - 1] + 1\n                # pi[i] = i - 1\n            if dp[i] > ans:\n                ans = dp[i]\n                # end_at = i\n\n        # paths = [0] * ans\n        # for i in range(ans - 1, -1, -1):\n        #     paths[i] = A[end_at]\n        #     end_at = pi[end_at]\n        # print(paths)\n\n        return ans\n\n\n\"\"\"\nOptimized\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An array of Integer\n    @return: an integer\n    \"\"\"\n    def longestIncreasingContinuousSubsequence(self, A):\n        if not A:\n            return 0\n\n        size = self.get_lics_size(A)\n        A.reverse()\n        _size = self.get_lics_size(A)\n\n        return max(size, _size)\n\n    def get_lics_size(self, A):\n        ans = size = 1\n\n        for i in range(1, len(A)):\n            if A[i] > A[i - 1]:\n                size += 1\n            else:\n                size = 1\n\n            if size > ans:\n                ans = size\n\n        return ans\n"
  },
  {
    "path": "lintcode/3_digit_counts.py",
    "content": "class Solution:\n    \"\"\"\n    @param: k: An integer\n    @param: n: An integer\n    @return: An integer denote the count of digit k in 1..n\n    \"\"\"\n    def digitCounts(self, k, n):\n        ans = 0\n        for i in range(n + 1):\n            ans += self.count(k, i)\n        return ans\n\n    def count(self, k, a):\n        if k == a == 0:\n            return 1\n\n        cnt = 0\n        while a:\n            if a % 10 == k:\n                cnt += 1\n            a //= 10\n        return cnt\n"
  },
  {
    "path": "lintcode/401_kth_smallest_number_in_sorted_matrix.py",
    "content": "import heapq\n\nclass Solution:\n    \"\"\"\n    @param: matrix: a matrix of integers\n    @param: k: An integer\n    @return: the kth smallest number in the matrix\n    \"\"\"\n    def kthSmallest(self, matrix, k):\n        ans = j = 0\n        heap, m, n = [], len(matrix), len(matrix[0])\n        for i in range(min(k, m)): heapq.heappush(heap, (matrix[i][0], i, 0))\n        while k > 0:\n            ans = heapq.heappop(heap)\n            j = ans[2] + 1\n            if j < n:\n                heapq.heappush(heap, (matrix[ans[1]][j], ans[1], j))\n            k -= 1\n        return ans[0]\n"
  },
  {
    "path": "lintcode/402_continuous_subarray_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: An integer array\n    @return: A list of integers includes the index of the first number and the index of the last number\n    \"\"\"\n    def continuousSubarraySum(self, A):\n        ans = [-1, -1]\n        if not A:\n            return ans\n\n        left = right = 0\n        _max = _sum = float('-inf')\n        for i in range(len(A)):\n            if _sum < 0:\n                _sum = A[i]\n                left = right = i\n            else:\n                _sum += A[i]\n                right = i\n\n            if _sum > _max:\n                _max = _sum\n                ans = [left, right]\n\n        return ans\n"
  },
  {
    "path": "lintcode/406_minimum_size_subarray_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: an array of integers\n    @param: s: An integer\n    @return: an integer representing the minimum size of subarray\n    \"\"\"\n    def minimumSize(self, nums, s):\n        if not nums or len(nums) == 0:\n            return -1\n        n = len(nums)\n        min_len = n + 1\n        l = r = t = 0\n        while r < n:\n            # Keep adding the next int into total until total >= s\n            while r < n and t < s:\n                t += nums[r]\n                r += 1\n\n            # Terminate iteration if all the children in nums have been added\n            if r >= n and t < s:\n                break\n\n            # Keep substracting the prev int from total until total < s\n            while l < r and t >= s:\n                t -= nums[l]\n                l += 1\n\n            # Save the min_size\n            min_len = min(min_len, r - l + 1)\n        return -1 if min_len > n else min_len\n"
  },
  {
    "path": "lintcode/40_implement_queue_by_two_stacks.py",
    "content": "class MyQueue:\n    def __init__(self, ):\n        self.stack1 = []\n        self.stack2 = []\n\n    \"\"\"\n    @param: element: An integer\n    @return: nothing\n    \"\"\"\n    def push(self, element):\n        self.stack1.append(element)\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def pop(self, ):\n        self.top()\n        return self.stack2.pop()\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def top(self, ):\n        # While `self.stack2` is empty, get element from `self.stack1`\n        # step0/ stack1: [1, 2, 3], stack2: []\n        # step1/ stack1: [], stack2: [3, 2, 1]\n        # step2/ stack1: [4, 5, 6], stack2: [3, 2] // 1\n        # step3/ stack1: [4, 5, 6], stack2: [] // 2, 3\n        # step4/ stack1: [7, 8], stack2: [6, 5, 4]\n        if not self.stack2:\n            while self.stack1:\n                self.stack2.append(self.stack1.pop())\n        return self.stack2[-1]\n"
  },
  {
    "path": "lintcode/414_divide_two_integers.py",
    "content": "class Solution:\n    def divide(self, a, b):\n        \"\"\"\n        :type a: int\n        :type b: int\n        :rtype: int\n        \"\"\"\n        INT_MAX = 0x7FFFFFFF\n        ans = 0\n\n        if not b:\n            return INT_MAX\n        if not a:\n            return ans\n\n        _a = -a if a < 0 else a\n        _b = -b if b < 0 else b\n\n        for i in range(31, -1, -1):\n            \"\"\"\n            let `ci = 1 << i = 2 ** i`\n            if `_a // _b >= ci`, that is `_a // ci >= _b`\n            => `(_a - _b * ci) // _b >= 0`, and `ans += ci`\n\n            start to approch `_a' // _b >= ci'`\n            where _a' = _a - _b * ci, i' = i - 1\n            \"\"\"\n            if (_a >> i) < _b:\n                continue\n            ans += 1 << i\n            _a -= _b << i\n\n        if a ^ b < 0:\n            ans = -ans\n\n        if ans > INT_MAX:\n            return INT_MAX\n        if ans < ~INT_MAX:\n            return ~INT_MAX\n        return ans\n"
  },
  {
    "path": "lintcode/415_valid_palindrome.py",
    "content": "class Solution:\n    def isPalindrome(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        if not s:\n            return True\n\n        s = s.lower()\n        n = len(s)\n        left, right = 0, n - 1\n\n        while left < right:\n            while left < right and not s[left].isalnum():\n                left += 1\n            while left < right and not s[right].isalnum():\n                right -= 1\n\n            if s[left] != s[right]:\n                return False\n\n            left += 1\n            right -= 1\n\n        return True\n"
  },
  {
    "path": "lintcode/417_valid_number.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: the string that represents a number\n    @return: whether the string is a valid number\n    \"\"\"\n    def isNumber(self, s):\n        if not s:\n            return False\n\n        n = len(s)\n        left, right = 0, n - 1\n        while left < n and s[left] == ' ':\n            left += 1\n        while right >= 0 and s[right] == ' ':\n            right -= 1\n        if left < n and s[left] in ('+', '-'):\n            left += 1\n\n        if left > right:\n            return False\n\n        if left != 0 or right != n - 1:\n            s = s[left:right + 1]\n\n        zero = ord('0')\n        nine = ord('9')\n        is_contained_dot = False\n        is_contained_num = False\n        for char in s:\n            if char == '.' and is_contained_dot:\n                return False\n            if not (char == '.' or zero <= ord(char) <= nine):\n                return False\n            if char == '.':\n                is_contained_dot = True\n            if zero <= ord(char) <= nine:\n                is_contained_num = True\n\n        return is_contained_num\n"
  },
  {
    "path": "lintcode/418_integer_to_roman.py",
    "content": "class Solution:\n    def intToRoman(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: str\n        \"\"\"\n        if not num:\n            return ''\n\n        # I, V, X, L, C, D, M\n        symbs = (\n            ('M', 1000),\n            ('CM', 900),\n            ('D', 500),\n            ('CD', 400),\n            ('C', 100),\n            ('XC', 90),\n            ('L', 50),\n            ('XL', 40),\n            ('X', 10),\n            ('IX', 9),\n            ('V', 5),\n            ('IV', 4),\n            ('I', 1),\n        )\n\n        ans = []\n\n        for symb, amount in symbs:\n            if not num:\n                break\n\n            while num >= amount:  # num - amount >= 0\n                num -= amount\n                ans.append(symb)\n\n        return ''.join(ans)\n"
  },
  {
    "path": "lintcode/419_roman_to_integer.py",
    "content": "class Solution:\n    def romanToInt(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not s:\n            return ans\n\n        symbs = {\n            'I': 1,\n            'V': 5,\n            'X': 10,\n            'L': 50,\n            'C': 100,\n            'D': 500,\n            'M': 1000,\n        }\n\n        ans += symbs[s[-1]]\n\n        for i in range(len(s) - 2, -1, -1):\n            if symbs[s[i]] >= symbs[s[i + 1]]:\n                ans += symbs[s[i]]\n            else:\n                ans -= symbs[s[i]]\n\n        return ans\n"
  },
  {
    "path": "lintcode/41_maximum_subarray.py",
    "content": "\"\"\"\nPrefix Sum: space optimization\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @return: A integer indicate the sum of max subarray\n    \"\"\"\n    def maxSubArray(self, A):\n        \"\"\"\n        the answer is the maximum segment sum,\n        that is, `S[i] - Smin`\n        \"\"\"\n        if not A:\n            return 0\n\n        ans = float('-inf')\n        S = Smin = 0\n        for i in range(len(A)):\n            S += A[i]\n\n            if S - Smin > ans:\n                ans = S - Smin\n\n            \"\"\"\n            since the sum of [i, j] in A is `S[j] - S[i - 1]`\n            so we need to find the `Smin` at the end of iteration\n            \"\"\"\n            if S < Smin:\n                Smin = S\n\n        return ans\n\n\n\"\"\"\nPrefix Sum\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @return: A integer indicate the sum of max subarray\n    \"\"\"\n    def maxSubArray(self, A):\n        \"\"\"\n        the answer is the maximum segment sum,\n        that is, `S[i] - Smin`\n        \"\"\"\n        if not A:\n            return 0\n\n        n = len(A)\n        ans = float('-inf')\n\n        Smin = 0\n        S = [0] * (n + 1)\n        for i in range(1, n + 1):\n            S[i] = S[i - 1] + A[i - 1]\n\n            if S[i] - Smin > ans:\n                ans = S[i] - Smin\n\n            \"\"\"\n            since the sum of [i, j] in A is `S[j] - S[i - 1]`\n            so we need to find the `Smin` at the end of iteration\n            \"\"\"\n            if S[i] < Smin:\n                Smin = S[i]\n\n        return ans\n"
  },
  {
    "path": "lintcode/42_maximum_subarray_ii.py",
    "content": "\"\"\"\nmain concept\n\nthere is MUST a separator to distinct that two subarrays\n\n`left[i]` means the maxsum before `i + 1`\n`right[i]` means the maxsum after `i - 1`\n\n        |<- the separator\nnums[i] | nums[i + 1]\n\nthe `ans` is to find the maximum of `left[i] + right[i + 1]`\n\"\"\"\n\n\nclass Solution:\n    def maxTwoSubArrays(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: int\n        \"\"\"\n        NOT_FOUND = 0\n        if not nums:\n            return NOT_FOUND\n\n        n = len(nums)\n        left = self.get_max_sums(nums, range(n))\n        right = self.get_max_sums(nums, range(n - 1, -1, -1))\n\n        ans = _INF = float('-inf')\n\n        for i in range(n - 1):\n            s = left[i] + right[i + 1]\n\n            if s > ans:\n                ans = s\n\n        return ans if ans > _INF else NOT_FOUND\n\n    def get_max_sums(self, nums, num_range):\n        res = [0] * len(nums)\n        smax = float('-inf')\n        s = smin = 0\n\n        for i in num_range:\n            s += nums[i]\n\n            if s - smin > smax:\n                smax = s - smin\n\n            if s < smin:\n                smin = s\n\n            res[i] = smax\n\n        return res\n"
  },
  {
    "path": "lintcode/430_scramble_string.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s1: A string\n    @param: s2: Another string\n    @return: whether s2 is a scrambled string of s1\n    \"\"\"\n    def isScramble(self, s1, s2):\n        if not s1 or not s2 or len(s1) != len(s2):\n            return False\n\n        n = len(s1)\n\n        \"\"\"\n        `dp[i][j][k]` means the substring in `s1` (start: `i`, len: `k`)\n        could be transformed into the substring in `s2` (start: `j`, len: `k`)\n        \"\"\"\n        dp = [[[False] * (n + 1) for _ in range(n)] for _ in range(n)]\n\n        for i in range(n):\n            for j in range(n):\n                dp[i][j][1] = (s1[i] == s2[j])\n\n        for k in range(2, n + 1):\n\n            for i in range(n):\n                \"\"\"\n                allow: i < n - k + 1 => i <= n - k\n                disallow: i > n - k\n                \"\"\"\n                if i + k > n:\n                    continue\n\n                for j in range(n):\n                    if j + k > n:\n                        continue\n\n                    for l in range(1, k):\n                        \"\"\"\n                        If its already calculated and possible to transform\n                        \"\"\"\n                        if dp[i][j][k]:\n                            continue\n\n                        \"\"\"\n                        * u1, u2: substring in s1\n                        * v1, v2: substring in s2\n                        * `l` == len(u1) == len(v1)\n                        * `k - l` == len(u2) == len(v2)\n\n                        case1: u1 -> v1, u2 -> v2\n                        `(dp[i][j][l] and dp[i + l][j + l][k - l])`\n                        - `dp[i][j][l]` means its possible to u1 -> v1\n                        - `dp[i + l][j + l][k - l]` => u2 -> v2\n\n                                   u1              u2\n                        s1: |`i`---`l`--->|`i+l`---`k-l`--->|\n                                   v1              v2\n                        s2: |`j`---`l`--->|`j+l`---`k-l`--->|\n\n                        case2: u1 -> v2, u2 -> v1\n                        `(dp[i][j + k - l][l] and dp[i + l][j][k - l])`\n                        - `dp[i][j + k - l][l]` => u1 -> v2\n                        - `dp[i + l][j][k - l]` => u2 -> v1\n\n                                   u1              u2\n                        s1: |`i`---`l`--->|`i+l`---`k-l`--->|\n                                   v1              v2\n                        s2: |`j`---`k-l`--->|`j+k-l`--`l`-->|\n                        \"\"\"\n                        if dp[i][j][l] and dp[i + l][j + l][k - l]:\n                            dp[i][j][k] = True\n                            continue\n\n                        if dp[i][j + k - l][l] and dp[i + l][j][k - l]:\n                            dp[i][j][k] = True\n\n        return dp[0][0][n]\n"
  },
  {
    "path": "lintcode/431_connected_component_in_undirected_graph.py",
    "content": "\"\"\"\nDefinition for a undirected graph node\nclass UndirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Union Find\n    \"\"\"\n    def connectedSet(self, nodes):\n        \"\"\"\n        :type nodes: list[UndirectedGraphNode]\n        :rtype: list[list[UndirectedGraphNode]]\n        \"\"\"\n        if not nodes:\n            return []\n\n        uf = {}\n\n        for node in nodes:\n            for neib in node.neighbors:\n                self.union(uf, node, neib)\n\n        ans = {}\n\n        for node in nodes:\n            # to correct root again\n            root = self.find(uf, node)\n\n            if root not in ans:\n                ans[root] = []\n\n            ans[root].append(node.label)\n\n        return list(ans.values())\n\n    def union(self, nodes, a, b):\n        _a = self.find(nodes, a)\n        _b = self.find(nodes, b)\n\n        if _a is not _b:\n            nodes[_b] = _a\n\n    def find(self, nodes, a):\n        if a not in nodes:\n            nodes[a] = a\n            return a\n        if nodes[a] is a:\n            return a\n\n        nodes[a] = self.find(nodes, nodes[a])\n        return nodes[a]\n\n\nclass Solution:\n    \"\"\"\n    DFS\n    \"\"\"\n    def connectedSet(self, nodes):\n        \"\"\"\n        :type nodes: list[UndirectedGraphNode]\n        :rtype: list[list[UndirectedGraphNode]]\n        \"\"\"\n        ans = []\n\n        if not nodes:\n            return ans\n\n        visited = set()\n\n        for node in nodes:\n            if node in visited:\n                continue\n\n            path = []\n            self.dfs(node, visited, path)\n            ans.append(sorted(path))\n\n        return ans\n\n    def dfs(self, a, visited, path):\n        visited.add(a)\n        path.append(a.label)\n\n        for b in a.neighbors:\n            if b in visited:\n                continue\n\n            self.dfs(b, visited, path)\n"
  },
  {
    "path": "lintcode/432_find_the_weak_connected_component_in_the_directed_graph.py",
    "content": "\"\"\"\nDefinition for a directed graph node\nclass DirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\nclass Solution:\n    def __init__(self):\n        self.nodes = {}\n\n    \"\"\"\n    @param {DirectedGraphNode[]} nodes a array of directed graph node\n    @return {int[][]} a connected set of a directed graph\n    \"\"\"\n    def connectedSet2(self, nodes):\n        # Build UnionFind\n        for node in nodes:\n            for nei in node.neighbors:\n                self.connect(nei.label, node.label)\n\n        # Categorify result\n        result = {}\n        root_label = ''\n        for node in nodes:\n            root_label = self.find(node.label)\n            if root_label not in result:\n                result[root_label] = []\n            result[root_label].append(node.label)\n        return result.values()\n\n    def connect(self, a, b):\n        root_a = self.find(a)\n        root_b = self.find(b)\n        if root_a is not root_b:\n            self.nodes[root_a] = root_b\n\n    def find(self, a):\n        if a not in self.nodes:\n            self.nodes[a] = a\n            return a\n        elif self.nodes[a] is a:\n            return a\n        self.nodes[a] = self.find(self.nodes[a])\n        return self.nodes[a]\n"
  },
  {
    "path": "lintcode/433_number_of_islands.py",
    "content": "class Solution:\n    def numIslands(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not grid or not grid[0]:\n            return ans\n\n        m, n = len(grid), len(grid[0])\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == 1:\n                    ans += 1\n                    self.dfs(grid, x, y)\n\n        return ans\n\n    def dfs(self, grid, x, y):\n        m, n = len(grid), len(grid[0])\n        grid[x][y] = 0\n\n        for dx, dy in (\n            (0, -1), (0, 1),\n            (-1, 0), (1, 0),\n        ):\n            _x = x + dx\n            _y = y + dy\n\n            if not (\n                0 <= _x < m and\n                0 <= _y < n and\n                grid[_x][_y] == 1\n            ):\n                continue\n\n            self.dfs(grid, _x, _y)\n"
  },
  {
    "path": "lintcode/434_number_of_islands_ii.py",
    "content": "\"\"\"\nDefinition for a point.\nclass Point:\n    def __init__(self, a=0, b=0):\n        self.x = a\n        self.y = b\n\"\"\"\n\n\nclass Solution:\n    def numIslands2(self, m, n, operators):\n        \"\"\"\n        :type m: int\n        :type n: int\n        :type operators: Point\n        :rtype: list[int]\n        \"\"\"\n        ans = []\n\n        if not m or not n or not operators:\n            return ans\n\n        cnt = 0\n        nodes = {}\n\n        for op in operators:\n            node = (op.x, op.y)\n\n            if node not in nodes:\n                nodes[node] = node\n                cnt += 1\n\n            for dx, dy in (\n                (0, -1), (0, 1),\n                (-1, 0), (1, 0),\n            ):\n                _x = op.x + dx\n                _y = op.y + dy\n\n                if not (\n                    0 <= _x < m and\n                    0 <= _y < n and\n                    (_x, _y) in nodes\n                ):\n                    continue\n\n                if self.union(nodes, node, (_x, _y)):\n                    cnt -= 1\n\n            ans.append(cnt)\n\n        return ans\n\n    def union(self, nodes, a, b):\n        _a = self.find(nodes, a)\n        _b = self.find(nodes, b)\n\n        if _a == _b:\n            return False\n\n        nodes[_b] = _a\n        return True\n\n    def find(self, nodes, a):\n        if a not in nodes:\n            nodes[a] = a\n            return a\n        if nodes[a] == a:\n            return a\n\n        nodes[a] = self.find(nodes, nodes[a])\n        return nodes[a]\n"
  },
  {
    "path": "lintcode/437_copy_books.py",
    "content": "\"\"\"\nDP: TLE\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: P: an array of integers\n    @param: k: An integer\n    @return: an integer\n    \"\"\"\n    def copyBooks(self, P, k):\n        if not P or not k:\n            return 0\n        n = len(P)\n        if n == 1:\n            return P[0]\n\n        if k > n:\n            k = n\n\n        INFINITY = float('inf')\n\n        \"\"\"\n        `dp[i][j]` means the minimum time to assign `i` books to `j` people\n        \"\"\"\n        dp = [[INFINITY] * k for _ in range(n)]\n\n        for j in range(k):\n            dp[0][j] = P[0]\n        for i in range(1, n):\n            dp[i][0] = dp[i - 1][0] + P[i]\n\n        for i in range(1, n):\n            for j in range(1, k):\n                if j > i:\n                    \"\"\"\n                    if `j > i`, means books more than copiers\n                    the people after `j`th people dont have to work\n                    \"\"\"\n                    dp[i][j] = dp[i][j - 1]\n                    continue\n\n                for h in range(j - 1, i + 1):\n                    \"\"\"\n                    `copied_pages` is the maximum copied pages,\n                    and also means the maximum time spent\n                    by the `j - 1` people before `j`\n\n                    if the `j - 1` people can copy as much as they can\n                    then `j`th man will be able to spend less time finishing it\n                    \"\"\"\n                    copied_pages = dp[i][0] - dp[h][0]\n                    if dp[h][j - 1] > copied_pages:\n                        copied_pages = dp[h][j - 1]\n                    if copied_pages < dp[i][j]:\n                        dp[i][j] = copied_pages\n\n        return dp[n - 1][k - 1]\n\n\n\"\"\"\nDP\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: P: an array of integers\n    @param: k: An integer\n    @return: an integer\n    \"\"\"\n    def copyBooks(self, P, k):\n        if not P or not k:\n            return 0\n        n = len(P)\n        if n == 1:\n            return P[0]\n\n        if k > n:\n            k = n\n\n        \"\"\"\n        `dp[i][j]` means the minimum time to assign `i` books to `j` people\n        \"\"\"\n        dp = [[0] * k for _ in range(n)]\n\n        for j in range(k):\n            dp[0][j] = P[0]\n        for i in range(1, n):\n            dp[i][0] = dp[i - 1][0] + P[i]\n\n        for j in range(1, k):\n            for i in range(1, j):\n                \"\"\"\n                if `j > i`, means books more than copiers\n                the people after `j`th people dont have to work\n                \"\"\"\n                dp[i][j] = dp[i][j - 1]\n\n            h = copied_pages = 0\n            for i in range(j, n):\n                \"\"\"\n                `h` means the maximum books `j - 1` men copied in shortest time\n                \"\"\"\n                while h < i and dp[h][j - 1] < dp[i][0] - dp[h][0]:\n                    h += 1\n\n                dp[i][j] = dp[h][j - 1]\n\n                if h == 0:\n                    continue\n\n                \"\"\"\n                check again the `h - 1` books\n\n                `copied_pages` is the maximum copied pages,\n                and also means the maximum time spent\n                by the `j - 1` people before `j`\n\n                if the `j - 1` people can copy as much as they can\n                then `j`th man will be able to spend less time finishing it\n                \"\"\"\n                copied_pages = dp[i][0] - dp[h - 1][0]\n                if dp[h - 1][j - 1] > copied_pages:\n                    copied_pages = dp[h - 1][j - 1]\n                if copied_pages < dp[i][j]:\n                    dp[i][j] = copied_pages\n\n        return dp[n - 1][k - 1]\n\n\n\"\"\"\nBinary Search\n\n1. the minimum spent time, that is `m`,\n   locates between `max(pages)` and `sum(pages)` (1 page spent 1 min)\n2. the `p` below means possible to finish work,\n   if the spent time less than `m`\n   and then the `k` people are impossible to finish that\n      t | ... m-2 m-1 m m+1 m+2 ...\n      p | ..F  F   F  T  T   T  T..\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: P: an array of integers\n    @param: k: An integer\n    @return: an integer\n    \"\"\"\n    def copyBooks(self, P, k):\n        if not P or not k:\n            return 0\n        n = len(P)\n        if n == 1:\n            return P[0]\n\n        if k > n:\n            k = n\n\n        left = right = P[0]\n        for i in range(1, len(P)):\n            if P[i] > left:\n                left = P[i]\n\n            right += P[i]\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if self.check_if_possible(P, mid, k):\n                right = mid\n            else:\n                left = mid\n\n        \"\"\"\n        MUST check `left` first, since we need the min spent time\n        \"\"\"\n        return left if self.check_if_possible(P, left, k) else right\n\n    def check_if_possible(self, P, spent_time, max_copiers):\n        \"\"\"\n        check if possible to copy all `pages` in `spent_time`\n        and participation is not more than `max_copiers`\n        \"\"\"\n        copied_pages, copiers = 0, 1\n\n        for i in range(len(P)):\n            \"\"\"\n            if a copier will spend more than `spent_time`\n            add one more copier in\n            \"\"\"\n            if copied_pages + P[i] > spent_time:\n                copied_pages = 0\n                copiers += 1\n            if copiers > max_copiers:\n                return False\n            copied_pages += P[i]\n\n        return True\n"
  },
  {
    "path": "lintcode/43_maximum_subarray_iii.py",
    "content": "\"\"\"\nhttp://www.cnblogs.com/sherylwang/p/5635665.html\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @param: k: An integer denote to find k non-overlapping subarrays\n    @return: An integer denote the sum of max k non-overlapping subarrays\n    \"\"\"\n    def maxSubArray(self, A, k):\n        if not A or not k or len(A) < k:\n            return 0\n\n        _INFINITY = float('-inf')\n        n = len(A)\n\n        \"\"\"\n        `G[i][j]` means the global max sum, to pick `j` arrays in [0, i)\n        `L[i][j]` means the local max sum, to pick `j` arrays in [0, i),\n                  and the `i - 1`th child MUST be included\n        \"\"\"\n        G = [[_INFINITY] * (k + 1) for _ in range(n + 1)]\n        L = [[_INFINITY] * (k + 1) for _ in range(n + 1)]\n\n        for i in range(n + 1):\n            L[i][0] = 0\n            G[i][0] = 0\n\n        for i in range(1, n + 1):\n            end = i\n            if k < end:\n                end = k\n            for j in range(1, end + 1):\n                L[i][j] = A[i - 1] + max(L[i - 1][j], G[i - 1][j - 1])\n                G[i][j] = max(L[i][j], G[i - 1][j])\n\n        return G[n][k]\n"
  },
  {
    "path": "lintcode/440_backpack_iii.py",
    "content": "\"\"\"\nOptimize Space\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an integer array\n    @param: V: an integer array\n    @param: m: an integer\n    @return: an integer\n    \"\"\"\n    def backPackIII(self, A, V, m):\n        if not A or not V or not m:\n            return 0\n\n        # `dp[w]` means the maximum value\n        # with weight `w`\n        dp = [0] * (m + 1)\n\n        _val = 0\n        for i in range(len(A)):\n            for w in range(A[i], m + 1):\n                _val = dp[w - A[i]] + V[i]\n                if _val > dp[w]:\n                    dp[w] = _val\n\n        return dp[m]\n\n\n\"\"\"\nOrigin\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an integer array\n    @param: V: an integer array\n    @param: m: an integer\n    @return: an integer\n    \"\"\"\n    def backPackIII(self, A, V, m):\n        if not A or not V or not m:\n            return 0\n\n        n = len(A)\n\n        # `dp[i][w]` means the maximum value\n        # with weight `w` in the former `i` items\n        dp = [[0] * (m + 1) for _ in range(n + 1)]\n\n        for i in range(1, n + 1):\n            for w in range(1, m + 1):\n                dp[i][w] = dp[i - 1][w]\n\n                if w >= A[i - 1]:\n                    dp[i][w] = max(\n                        dp[i][w],\n                        dp[i][w - A[i - 1]] + V[i - 1]\n                    )\n\n        return dp[n][w]\n"
  },
  {
    "path": "lintcode/442_implement_trie.py",
    "content": "class TrieNode:\n    def __init__(self):\n        self.end_of = None\n        self.children = {}\n\n\nclass Trie:\n    def __init__(self):\n        self.root = TrieNode()\n\n    \"\"\"\n    @param: word: a word\n    @return: nothing\n    \"\"\"\n    def insert(self, word):\n        if word is None:\n            return\n\n        node = self.root\n\n        for c in word:\n            if c not in node.children:\n                node.children[c] = TrieNode()\n\n            node = node.children[c]\n\n        node.end_of = word\n\n    \"\"\"\n    @param: word: A string\n    @return: if the word is in the trie.\n    \"\"\"\n    def search(self, word):\n        if word is None:\n            return False\n\n        node = self.root\n\n        for c in word:\n            if c not in node.children:\n                return False\n\n            node = node.children[c]\n\n        return node.end_of == word\n\n    \"\"\"\n    @param: prefix: A string\n    @return: if there is any word in the trie that starts with the given prefix.\n    \"\"\"\n    def startsWith(self, prefix):\n        if prefix is None:\n            return False\n\n        node = self.root\n\n        for c in prefix:\n            if c not in node.children:\n                return False\n\n            node = node.children[c]\n\n        return True\n"
  },
  {
    "path": "lintcode/443_two_sum_greater_than_target.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an array of integer\n    @param: target: An integer\n    @return: an integer\n    \"\"\"\n    def twoSum2(self, A, target):\n        ans = 0\n        if not A or len(A) < 2:\n            return ans\n\n        A.sort()\n\n        left, right = 0, len(A) - 1\n        while left < right:\n            # if minimum + maximum still <= target\n            # ignore the 2nd, 3rd maximum\n            if A[left] + A[right] <= target:\n                left += 1\n                continue\n\n            # if minimum + maximum > target\n            # we can ensure the 2nd, 3rd minimum also fit demand\n            ans += right - left\n            right -= 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/447_search_in_a_big_sorted_array.py",
    "content": "\"\"\"\nTest Case:\n\n# if `reader.get(m) == target` when binary searching\n# should set the `mid` as the right bound to keep looking for the minimum index\n[1,1,1,1,2,2,3,3,3,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,10,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,13,14,14,14,14,14,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,18,18,19,19,19,19,20,20,20,20,20,20,20,20,20]\n4\n\n# error occurred when `if not reader or not target:`\n[0,0,1,1]\n0\n\"\"\"\n\nclass Solution:\n    \"\"\"\n    @param: reader: An instance of ArrayReader.\n    @param: target: An integer\n    @return: An integer which is the first index of target.\n    \"\"\"\n    def searchBigSortedArray(self, reader, target):\n        end = 0\n        while reader.get(end) < target:\n            # `+1` is to avoid `end == 0`\n            end = end * 2 + 1\n\n        l, m, r = 0, 0, end\n        while l + 1 < r:\n            m = l + (r - l) // 2\n            if reader.get(m) < target:\n                l = m\n            else:\n                r = m\n\n        for i in [l, r]:\n            if reader.get(i) == target:\n                return i\n        return -1\n"
  },
  {
    "path": "lintcode/450_reverse_nodes_in_k_group.py",
    "content": "\"\"\"\nDefinition for singly-linked list.\nclass ListNode:\n    def __init__(self, x):\n        self.val = x\n        self.next = None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: a ListNode\n    @param: k: An integer\n    @return: a ListNode\n    \"\"\"\n    def reverseKGroup(self, head, k):\n        if not head:\n            return\n\n        dummy = ListNode(0)\n        dummy.next = head\n\n        head = dummy\n        while head:\n            head = self.reverse_next_kth(head, k)\n\n        return dummy.next\n\n    def find_kth(self, head, k):\n        for i in range(k):\n            if not head:\n                return\n            head = head.next\n        return head\n\n    def reverse(self, head):\n        pre = nxt = None\n        while head:\n            nxt = head.next\n            head.next = pre\n            pre = head\n            head = nxt\n        return pre\n\n    def reverse_next_kth(self, head, k):\n        nk = self.find_kth(head, k)\n        if not nk:\n            return\n        nk_nxt = nk.next\n        n1_pre = head\n        n1 = head.next\n\n        nk.next = None\n\n        self.reverse(n1)\n        n1_pre.next = nk\n        n1.next = nk_nxt\n        return n1\n"
  },
  {
    "path": "lintcode/453_flatten_binary_tree_to_linked_list.py",
    "content": "\"\"\"\nMain Concept:\nFor given tree:\n1-5-6\n =2-4\n   =3\ntake postorder traversal, and the visited order will be `3,4,2,1,5,6`\n\n1. rebase the right child with the last right child in left child\nwhen visit `2`\n1-5-6\n =2=3-4\n\n2. move the left child to the right\nwhen visit `2`\n1-5-6\n =2-3-4\n\n3. keep doing (1) and (2)\nwhen visit `1`\n1-2-3-4-5-6\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: a TreeNode, the root of the binary tree\n    @return:\n    \"\"\"\n    def flatten(self, root):\n        if not root:\n            return\n\n        self.flatten(root.left)\n        self.flatten(root.right)\n\n        if not root.left:\n            return\n\n        node = root.left\n\n        while node.right:\n            node = node.right\n\n        node.right = root.right\n        root.right = root.left\n        root.left = None\n"
  },
  {
    "path": "lintcode/457_classical_binary_search.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: An integer array sorted in ascending order\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def findPosition(self, A, target):\n        if not A:\n            return -1\n\n        left, right = 0, len(A) - 1\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if A[mid] == target:\n                return mid\n            if A[mid] < target:\n                left = mid\n            else:\n                right = mid\n\n        if A[left] == target:\n            return left\n        if A[right] == target:\n            return right\n        return -1\n"
  },
  {
    "path": "lintcode/458_last_position_of_target.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: An integer array sorted in ascending order\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def lastPosition(self, nums, target):\n        if not nums or not target:\n            return -1\n\n        l, m, r = 0, 0, len(nums) - 1\n        while l + 1 < r:\n            m = l + (r - l) // 2\n            if nums[m] > target:\n                r = m\n            else:\n                l = m\n\n        \"\"\"\n        considering the edge case: [1, 1, 1, 1]\n        we've compared all child above but the both ends\n        so we should check the both ends\n        \"\"\"\n        if nums[r] == target:\n            return r\n        elif nums[l] == target:\n            return l\n        else:\n            return -1\n"
  },
  {
    "path": "lintcode/459_closest_number_in_sorted_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an integer array sorted in ascending order\n    @param: target: An integer\n    @return: an integer\n    \"\"\"\n    def closestNumber(self, A, target):\n        if not A or not target:\n            return -1\n\n        l, m, r = 0, 0, len(A) - 1\n\n        while l + 1 < r:\n            m = l + (r - l) // 2\n            if A[m] == target:\n                return m\n            elif A[m] > target:\n                r = m\n            else:\n                l = m\n\n        if A[r] - target > target - A[l]:\n            return l\n        else:\n            return r\n"
  },
  {
    "path": "lintcode/45_maximum_subarray_difference.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: A list of integers\n    @return: An integer indicate the value of maximum difference between two substrings\n    \"\"\"\n    def maxDiffSubArrays(self, A):\n        if not A:\n            return 0\n\n        n = len(A)\n        B = [-1 * num for num in A]\n        Lmin = self.get_sum(B, range(n), factor=-1)\n        Lmax = self.get_sum(A, range(n), factor=1)\n        Rmin = self.get_sum(B, range(n - 1, -1, -1), factor=-1)\n        Rmax = self.get_sum(A, range(n - 1, -1, -1), factor=1)\n\n        ans = float('-inf')\n        for i in range(n - 1):\n            ans = max(\n                ans,\n                Lmax[i] - Rmin[i + 1],\n                Rmax[i + 1] - Lmin[i]\n            )\n\n        return ans\n\n    def get_sum(self, A, scope, factor):\n        \"\"\"\n        factor ==  1: max sum\n        factor == -1: min sum\n        \"\"\"\n\n        M = [0] * len(A)\n        Smax = float('-inf')\n        S = Smin = 0\n\n        for i in scope:\n            S += A[i]\n            if S - Smin > Smax:\n                Smax = S - Smin\n            if S < Smin:\n                Smin = S\n            M[i] = Smax * factor\n\n        return M\n"
  },
  {
    "path": "lintcode/460_k_closest_numbers_in_sorted_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an integer array\n    @param: target: An integer\n    @param: k: An integer\n    @return: an integer array\n    \"\"\"\n    def kClosestNumbers(self, A, target, k):\n        if not A:\n            return []\n\n        n = len(A)\n\n        \"\"\"\n        if `b` in `A`:\n            [a, b, b, b, c]\n                      l  r\n        else:\n            [a, c, d, e, f]\n             l  r\n        \"\"\"\n        left, mid, right = 0, 0, n - 1\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] <= target:\n                left = mid\n            else:\n                right = mid\n\n        \"\"\"\n        # handle out of range\n        if `left` less than `0`\n            only append `A[right]`\n        if `right` great than `n - 1`\n            only append `A[left]`\n\n        # handle closest\n        append first if that `num` is more closer `target`\n        \"\"\"\n        ans = [0] * k\n        for i in range(k):\n            if left < 0:\n                ans[i] = A[right]\n                right += 1\n            elif right >= n:\n                ans[i] = A[left]\n                left -= 1\n            elif A[right] - target < target - A[left]:\n                ans[i] = A[right]\n                right += 1\n            else:\n                ans[i] = A[left]\n                left -= 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/461_kth_smallest_numbers_in_unsorted_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: K: An integer\n    @param: A: An integer array\n    @return: kth smallest element\n    \"\"\"\n    def kthSmallest(self, K, A):\n        \"\"\"\n        the index of `K`th child is `K - 1`\n        \"\"\"\n        return self.quick_select(K - 1, A, 0, len(A) - 1)\n\n    def quick_select(self, k, A, start, end):\n        if start >= end:\n            return A[end]\n\n        left, right = start, end\n        pivot = A[(start + end) // 2]\n\n        while left <= right:\n            while left <= right and A[left] < pivot:\n                left += 1\n            while left <= right and A[right] > pivot:\n                right -= 1\n\n            if left <= right:\n                A[left], A[right] = A[right], A[left]\n                left += 1\n                right -= 1\n\n        if start <= k <= right:\n            return self.quick_select(k, A, start, right)\n        elif left <= k <= end:\n            return self.quick_select(k, A, left, end)\n        else:\n            return A[k]\n"
  },
  {
    "path": "lintcode/462_total_occurrence_of_target.py",
    "content": "class Solution:\n    def totalOccurrence(self, A, target):\n        \"\"\"\n        :type A: List[int]\n        :type target: int\n        :rtype: int\n\n        given A == [a, b, b, b, c]\n                       s     e\n\n        using binary searching to find `s` and `e`\n        ans is `e - s + 1`\n\n        * s: start, e: end, l: left, r: right\n             [a, b, b, b, c]\n        r1    l  r,s\n        r2           e,l  r\n        \"\"\"\n        if not A:\n            return 0\n\n        n = len(A)\n\n        left, mid, right = 0, 0, n - 1\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] < target:\n                left = mid\n            else:\n                right = mid\n\n        start = left if A[left] == target else right\n\n        if A[start] != target:\n            return 0\n\n        left, mid, right = 0, 0, n - 1\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] <= target:\n                left = mid\n            else:\n                right = mid\n\n        end = right if A[right] == target else left\n\n        return end - start + 1\n"
  },
  {
    "path": "lintcode/465_kth_smallest_sum_in_two_sorted_arrays.py",
    "content": "import heapq\n\n\"\"\"\nAssuming: len(A) == len(B) == 3\n\nTo find the result(min of A[i]+B[j]), we got a 3x3 matrix:\nAB | 0 | 1 | 2 |\n 0 | a | b | c |\n 1 | d | e | f |\n 2 | g | h | i |\n\n 1. put the first column (0, j) into heap, these child is the min for each row\n 2. get the minest one, and move the `x` pointer forward, put the child at (x+1, y)\n 3. keep find the minest one in current heap, then we can find the kth child\n\"\"\"\n\nclass Solution:\n\n    \"\"\"\n    @param: A: an integer arrays sorted in ascending order\n    @param: B: an integer arrays sorted in ascending order\n    @param: k: An integer\n    @return: An integer\n    \"\"\"\n    def kthSmallestSum(self, A, B, k):\n        m, n = len(A), len(B)\n        ans = j = 0\n        heap = []\n        for i in range(min(m, k)): heapq.heappush(heap, (A[i] + B[0], i, 0))\n        while k > 0:\n            ans = heapq.heappop(heap)\n            j = ans[2] + 1\n            if j < n:\n                heapq.heappush(heap, (A[ans[1]] + B[j], ans[1], j))\n            k -= 1\n        return ans[0]\n"
  },
  {
    "path": "lintcode/469_identical_binary_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: the root of binary tree A.\n    @param: B: the root of binary tree B.\n    @return: true if they are identical, or false.\n    \"\"\"\n    def isIdentical(self, A, B):\n        if not A and not B:\n            return True\n\n        if not A or not B:\n            return False\n\n        if A.val != B.val:\n            return False\n\n        return (\n            self.isIdentical(A.left, B.left) and\n            self.isIdentical(A.right, B.right)\n        )\n"
  },
  {
    "path": "lintcode/471_top_k_frequent_words.py",
    "content": "class Solution:\n    \"\"\"\n    @param: words: an array of string\n    @param: k: An integer\n    @return: an array of string\n    \"\"\"\n    def topKFrequentWords(self, words, k):\n        if not words or not k:\n            return []\n\n        F = {}\n        for word in words:\n            F[word] = F.get(word, 0) + 1\n\n        W = [(freq, word) for word, freq in F.items()]\n        W.sort(key=lambda item: (-item[0], item[1]))\n\n        return [W[i][1] for i in range(k)]\n"
  },
  {
    "path": "lintcode/472_binary_tree_path_sum_iii.py",
    "content": "\"\"\"\nDefinition of ParentTreeNode:\nclass ParentTreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.parent, self.left, self.right = None, None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: the root of binary tree\n    @param: target: An integer\n    @return: all valid paths\n    \"\"\"\n    def binaryTreePathSum3(self, root, target):\n        \"\"\"\n        1. using `dfs` to visit every node in that tree\n        2. once enter a node, start to find the path based on it\n           to parent, left child, and right child.\n        \"\"\"\n        ans = []\n        self.dfs(root, target, ans)\n        return ans\n\n    def dfs(self, node, target, ans):\n        if not node:\n            return\n\n        self.find_path(node, node, target, ans, [])\n\n        self.dfs(node.left, target, ans)\n        self.dfs(node.right, target, ans)\n\n    def find_path(self, node, start, remaining, ans, path):\n        path.append(node.val)\n\n        remaining -= node.val\n        if remaining == 0:\n            ans.append(path[:])\n\n        if node.parent and node.parent is not start:\n            self.find_path(node.parent, node, remaining, ans, path)\n        if node.left and node.left is not start:\n            self.find_path(node.left, node, remaining, ans, path)\n        if node.right and node.right is not start:\n            self.find_path(node.right, node, remaining, ans, path)\n\n        path.pop()\n"
  },
  {
    "path": "lintcode/473_add_and_search_word.py",
    "content": "class Trie:\n    def __init__(self):\n        self.root = {}\n\n    def insert(self, string):\n        if not string:\n            return\n        parent = self.root\n        for char in string:\n            if char in parent:\n                parent = parent[char]\n            else:\n                parent[char] = {}\n                parent = parent[char]\n        parent['_end'] = True\n\n    def search(self, string):\n        if not string:\n            return False\n        parent = self.root\n        for char in string:\n            if char in parent:\n                parent = parent[char]\n            else:\n                return False\n        return True\n\n    def search_in_regex(self, string):\n        if not string:\n            return False\n        return self._search_in_regex(string, self.root, 0)\n\n    def _search_in_regex(self, string, parent, i):\n        if i == len(string):\n            return parent.get('_end', False)\n        result = False\n        if string[i] == '.':\n            for child in parent:\n                if child[0] != '_' and self._search_in_regex(string, parent[child], i + 1):\n                    result = True\n        elif string[i] in parent:\n            if self._search_in_regex(string, parent[string[i]], i + 1):\n                result = True\n        return result\n\nclass WordDictionary:\n    def __init__(self):\n        self.trie = Trie()\n\n    \"\"\"\n    @param: word: Adds a word into the data structure.\n    @return: nothing\n    \"\"\"\n    def addWord(self, word):\n        if not word:\n            return\n        self.trie.insert(word)\n\n    \"\"\"\n    @param: word: A word could contain the dot character '.' to represent any one letter.\n    @return: if the word is in the data structure.\n    \"\"\"\n    def search(self, word):\n        if not word:\n            return False\n        return self.trie.search_in_regex(word)\n\n\n# Your WordDictionary object will be instantiated and called as such:\n# wordDictionary = WordDictionary()\n# wordDictionary.addWord(\"word\")\n# wordDictionary.search(\"pattern\")\n"
  },
  {
    "path": "lintcode/474_lowest_common_ancestor_ii.py",
    "content": "\"\"\"\nThe node has an extra attribute parent which point to the father of itself.\nThe root's parent is null.\n\n\nDefinition of ParentTreeNode:\nclass ParentTreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.parent, self.left, self.right = None, None, None\n\"\"\"\n\n\nclass Solution:\n    def lowestCommonAncestorII(self, root, a, b):\n        \"\"\"\n        :type root: ParentTreeNode\n        :type a: ParentTreeNode\n        :type b: ParentTreeNode\n        :rtype: ParentTreeNode\n        \"\"\"\n        if not root:\n            return root\n\n        nodes = set()\n\n        while a:\n            nodes.add(a)\n            a = a.parent\n\n        while b:\n            if b in nodes:\n                return b\n            b = b.parent\n\n        return root\n"
  },
  {
    "path": "lintcode/475_binary_tree_maximum_path_sum_ii.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def maxPathSum2(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        left = self.maxPathSum2(root.left)\n        right = self.maxPathSum2(root.right)\n\n        return root.val + max(0, left, right)\n"
  },
  {
    "path": "lintcode/479_second_max_of_array.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: An integer array\n    @return: The second max number in the array.\n    \"\"\"\n    def secondMax(self, A):\n        if not A:\n            return\n\n        max1 = max2 = float('-inf')\n        for a in A:\n            if a > max1:\n                max2 = max1\n                max1 = a\n                continue\n            if a > max2:\n                max2 = a\n\n        return max2\n"
  },
  {
    "path": "lintcode/480_binary_tree_paths.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def binaryTreePaths(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: list[str]\n        \"\"\"\n        ans = []\n        if not root:\n            return ans\n\n        self.dfs(root, ans, [])\n\n        return ans\n\n    def dfs(self, node, ans, path):\n        path.append(str(node.val))\n\n        if not node.left and not node.right:\n            ans.append('->'.join(path))\n            path.pop()\n            return\n\n        if node.left:\n            self.dfs(node.left, ans, path)\n\n        if node.right:\n            self.dfs(node.right, ans, path)\n\n        path.pop()\n"
  },
  {
    "path": "lintcode/486_merge_k_sorted_arrays.py",
    "content": "from heapq import heappop, heappush\n\n\nclass Solution:\n    \"\"\"\n    @param: G: k sorted integer arrays\n    @return: a sorted array\n    \"\"\"\n    def mergekSortedArrays(self, G):\n        ans = []\n        if not G:\n            return ans\n\n        heap = []\n        for i in range(len(G)):\n            if not G[i]:\n                continue\n\n            heappush(heap, (G[i][0], i, 0))\n\n        while heap:\n            num, x, y = heappop(heap)\n            ans.append(num)\n            if y + 1 < len(G[x]):\n                heappush(heap, (G[x][y + 1], x, y + 1))\n\n        return ans\n"
  },
  {
    "path": "lintcode/494_implement_stack_by_two_queues.py",
    "content": "from lintcode import ListNode\n\n\nclass Stack:\n    def __init__(self):\n        self.dummy = self.tail = ListNode(-1)\n\n    \"\"\"\n    @param: x: An integer\n    @return: nothing\n    \"\"\"\n    def push(self, x):\n        node = ListNode(x)\n        node.pre = self.tail\n        self.tail.nxt = node\n        self.tail = node\n\n    \"\"\"\n    @return: nothing\n    \"\"\"\n    def pop(self):\n        if self.isEmpty():\n            return\n        node = self.tail\n        self.tail = node.pre\n        self.tail.nxt = node.pre = None\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def top(self):\n        if self.isEmpty():\n            return\n        return self.tail.val\n\n    \"\"\"\n    @return: True if the stack is empty\n    \"\"\"\n    def isEmpty(self):\n        return self.dummy is self.tail\n"
  },
  {
    "path": "lintcode/496_toy_factory.py",
    "content": "\"\"\"\nYour object will be instantiated and called as such:\nty = ToyFactory()\ntoy = ty.getToy(type)\ntoy.talk()\n\"\"\"\nclass Toy:\n    def talk(self):\n        raise NotImplementedError('This method should have implemented.')\n\n\nclass Dog(Toy):\n    def talk(self):\n        print 'Wow'\n\n\nclass Cat(Toy):\n    def talk(self):\n        print 'Meow'\n\n\nclass ToyFactory:\n    # @param {string} shapeType a string\n    # @return {Toy} Get object of the type\n    def getToy(self, type):\n        if type == 'Dog':\n            return Dog()\n        if type == 'Cat':\n            return Cat()\n"
  },
  {
    "path": "lintcode/497_shape_factory.py",
    "content": "\"\"\"\nYour object will be instantiated and called as such:\nsf = ShapeFactory()\nshape = sf.getShape(shapeType)\nshape.draw()\n\"\"\"\nclass Shape:\n    def draw(self):\n        raise NotImplementedError('This method should have implemented.')\n\n\nclass Triangle(Shape):\n    def draw(self):\n        print '  /\\\\'\n        print ' /  \\\\'\n        print '/____\\\\'\n\n\nclass Rectangle(Shape):\n    def draw(self):\n        print ' ----'\n        print '|    |'\n        print ' ----'\n\n\nclass Square(Shape):\n    def draw(self):\n        print ' ----'\n        print '|    |'\n        print '|    |'\n        print ' ----'\n\n\nclass ShapeFactory:\n    # @param {string} shapeType a string\n    # @return {Shape} Get object of type Shape\n    def getShape(self, shapeType):\n        if shapeType == 'Triangle':\n            return Triangle()\n        if shapeType == 'Rectangle':\n            return Rectangle()\n        if shapeType == 'Square':\n            return Square()\n"
  },
  {
    "path": "lintcode/498_parking_lot.py",
    "content": "VEHICLE_ID = {\n    'MOTOCYCLE': 'MOTOCYCLE',\n    'CAR': 'CAR',\n    'BUS': 'BUS',\n}\n\n\nclass Vehicle:\n    def __init__(self):\n        self.type = ''\n        self.costs = 0\n        self.at_level = None\n        self.at_spots = None\n\n    def unpark(self):\n        if not self.at_level:\n            return\n\n        for x, y in self.at_spots:\n            self.at_level.spots[x, y] = None\n\n        self.at_level = None\n        self.at_spots = None\n\n\nclass Motorcycle(Vehicle):\n    def __init__(self):\n        self.type = VEHICLE_ID['MOTOCYCLE']\n        self.costs = 1\n\n\nclass Car(Vehicle):\n    def __init__(self):\n        self.type = VEHICLE_ID['CAR']\n        self.costs = 1\n\n\nclass Bus(Vehicle):\n    def __init__(self):\n        self.type = VEHICLE_ID['BUS']\n        self.costs = 5\n\n\nclass Level:\n    def __init__(self, id, m, n):\n        self.id = id\n        self.m = m\n        self.n = n\n        self.spots = {}\n\n    def get_range(self, vehicle_type):\n        quarter = self.n // 4\n\n        if vehicle_type == VEHICLE_ID['BUS']:\n            return range(quarter * 3, self.n)\n\n        if vehicle_type == VEHICLE_ID['CAR']:\n            return range(quarter, self.n)\n\n        return range(self.n)\n\n    def park_vehicle(self, vehicle):\n        \"\"\"\n        :type vehicle: Vehicle\n        :rtype: bool\n        \"\"\"\n        RANGE = self.get_range(vehicle.type)\n\n        for x in range(self.m):\n            gotcha = 0\n\n            for y in RANGE:\n                if self.spots.get((x, y)):\n                    gotcha = 0\n                    continue\n\n                gotcha += 1\n\n                if gotcha == vehicle.costs:\n                    spots = []\n\n                    for i in range(y, y - gotcha, -1):\n                        spots.append((x, i))\n                        self.spots[x, i] = vehicle\n\n                    vehicle.at_level = self\n                    vehicle.at_spots = spots\n                    return True\n\n        return False\n\n\nclass ParkingLot:\n    def __init__(self, k, m, n):\n        \"\"\"\n        :type k: int, number of levels\n        :type m: int, each level has m rows of spots\n        :type n: int, each row has n spots\n        \"\"\"\n        self.levels = [Level(i, m, n) for i in range(k)]\n\n    def park_vehicle(self, vehicle):\n        \"\"\"\n        :type vehicle: Vehicle\n        :rtype: bool\n        \"\"\"\n        if any(\n            level.park_vehicle(vehicle)\n            for level in self.levels\n        ):\n            return True\n\n        return False\n\n    def unpark_vehicle(self, vehicle):\n        \"\"\"\n        :type vehicle: Vehicle\n        \"\"\"\n        vehicle.unpark()\n"
  },
  {
    "path": "lintcode/499_word_count.py",
    "content": "class WordCount:\n\n    # @param {str} line a text, for example \"Bye Bye see you next\"\n    def mapper(self, _, line):\n        for word in line.split():\n            yield word, 1\n\n    # @param key is from mapper\n    # @param values is a set of value with the same key\n    def reducer(self, key, values):\n        yield key, sum(values)\n"
  },
  {
    "path": "lintcode/4_ugly_number_ii.py",
    "content": "\"\"\"\nMain Concept:\n\n1. start from 1 => `ans = [1]`\n2. use `i2, i3, i5` to record current used in `ans`\n3. if the candidates is not ahead `ans[-1]`, move forward\n4. append the minimum candidate to `ans`\n\"\"\"\n\n\nclass Solution:\n    def nthUglyNumber(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if not n:\n            return 0\n\n        ans = [1]\n        i2 = i3 = i5 = 0\n\n        for _ in range(1, n):\n            while ans[i2] * 2 <= ans[-1]:\n                i2 += 1\n            while ans[i3] * 3 <= ans[-1]:\n                i3 += 1\n            while ans[i5] * 5 <= ans[-1]:\n                i5 += 1\n\n            ans.append(min((\n                ans[i2] * 2,\n                ans[i3] * 3,\n                ans[i5] * 5,\n            )))\n\n        return ans[-1]\n"
  },
  {
    "path": "lintcode/500_inverted_index.py",
    "content": "'''\nDefinition of Document\nclass Document:\n    def __init__(self, id, cotent):\n        self.id = id\n        self.content = content\n'''\nclass Solution:\n    # @param {Document[]} docs a list of documents\n    # @return {dict(string, int[])} an inverted index\n    def invertedIndex(self, docs):\n        if not docs or len(docs) < 1:\n            return {}\n        result = {}\n        for doc in docs:\n            if not doc.content:\n                continue\n            for word in doc.content.split():\n                if word not in result:\n                    result[word] = []\n                if doc.id not in result[word]:\n                    result[word].append(doc.id)\n        return result\n"
  },
  {
    "path": "lintcode/501_mini_twitter.py",
    "content": "\"\"\"\nDefinition of Tweet:\nclass Tweet:\n    @classmethod\n    def create(cls, user_id, tweet_text):\n         # This will create a new tweet object,\n         # and auto fill id\n\"\"\"\n\n\nclass MiniTwitter:\n    def __init__(self):\n        self.timestamp = 0\n        self.tweets = {}\n        self.followings = {}\n\n    \"\"\"\n    @param: user_id: An integer\n    @param: tweet_text: a string\n    @return: a tweet\n    \"\"\"\n    def postTweet(self, user_id, tweet_text):\n        if user_id not in self.tweets:\n            self.tweets[user_id] = []\n\n        self.timestamp += 1\n        self.tweets[user_id].append((\n            self.timestamp,\n            Tweet.create(user_id, tweet_text),\n        ))\n\n        return self.tweets[user_id][-1][1]\n\n    \"\"\"\n    @param: user_id: An integer\n    @return: a list of 10 new feeds recently and sort by timeline\n    \"\"\"\n    def getNewsFeed(self, user_id):\n        res = []\n\n        if user_id in self.tweets:\n            res.extend(self.tweets[user_id][-10:])\n\n        if user_id in self.followings:\n            for follow_id in self.followings[user_id]:\n                if follow_id in self.tweets:\n                    res.extend(self.tweets[follow_id][-10:])\n\n        if not res:\n            return []\n\n        res.sort()\n        return [tweet for _, tweet in res[-10:]][::-1]\n\n    \"\"\"\n    @param: user_id: An integer\n    @return: a list of 10 new posts recently and sort by timeline\n    \"\"\"\n    def getTimeline(self, user_id):\n        if user_id not in self.tweets:\n            return []\n\n        return [tweet for _, tweet in self.tweets[user_id][-10:]][::-1]\n\n    \"\"\"\n    @param: from_id: An integer\n    @param: to_id: An integer\n    @return: nothing\n    \"\"\"\n    def follow(self, from_id, to_id):\n        if from_id not in self.followings:\n            self.followings[from_id] = set()\n\n        if to_id in self.followings[from_id]:\n            return\n\n        self.followings[from_id].add(to_id)\n\n    \"\"\"\n    @param: from_id: An integer\n    @param: to_id: An integer\n    @return: nothing\n    \"\"\"\n    def unfollow(self, from_id, to_id):\n        if from_id not in self.followings:\n            return\n\n        if to_id not in self.followings[from_id]:\n            return\n\n        self.followings[from_id].discard(to_id)\n"
  },
  {
    "path": "lintcode/502_mini_cassandra.py",
    "content": "\"\"\"\nDefinition of Column:\nclass Column:\n    def __init__(self, key, value):\n        self.key = key\n        self.value = value\n\"\"\"\n\n\nclass MiniCassandra:\n\n    storage = {}\n\n    \"\"\"\n    @param: raw_key: a string\n    @param: column_key: An integer\n    @param: column_value: a string\n    @return: nothing\n    \"\"\"\n    def insert(self, raw_key, column_key, column_value):\n        if raw_key not in self.storage:\n            self.storage[raw_key] = {}\n\n        self.storage[raw_key][column_key] = Column(column_key, column_value)\n\n    \"\"\"\n    @param: raw_key: a string\n    @param: column_start: An integer\n    @param: column_end: An integer\n    @return: a list of Columns\n    \"\"\"\n    def query(self, raw_key, column_start, column_end):\n        if raw_key not in self.storage:\n            return []\n\n        result = [\n            column\n            for column_key, column in self.storage[raw_key].items()\n            if column_start <= column_key <= column_end\n        ]\n\n        return sorted(result, key=lambda column: column.key)\n"
  },
  {
    "path": "lintcode/503_anagram_map_reduce.py",
    "content": "class Anagram:\n\n    # @param {str} line a text, for example \"Bye Bye see you next\"\n    def mapper(self, _, line):\n        for word in line.split():\n            yield ''.join(sorted(word.lower())), word\n\n    # @param key is from mapper\n    # @param values is a set of value with the same key\n    def reducer(self, key, values):\n        yield key, values\n"
  },
  {
    "path": "lintcode/504_inverted_index_map_reduce.py",
    "content": "'''\nDefinition of Document\nclass Document:\n    def __init__(self, id, cotent):\n        self.id = id\n        self.content = content\n'''\nclass InvertedIndex:\n\n    # @param {Document} value is a document\n    def mapper(self, _, value):\n        for word in value.content.split():\n            yield word, value.id\n\n    # @param key is from mapper\n    # @param values is a set of value with the same key\n    def reducer(self, key, values):\n        yield key, sorted(list(set(values)))\n"
  },
  {
    "path": "lintcode/505_web_logger.py",
    "content": "class WebLogger:\n    def __init__(self):\n        dummy = []\n        dummy[:] = [dummy, dummy, -1]\n        self.dummy = dummy\n        self.size = 0\n\n    \"\"\"\n    @param: timestamp: An integer\n    @return: nothing\n    \"\"\"\n    def hit(self, timestamp):\n        tail = self.dummy[0]\n\n        tail[1] = self.dummy[0] = _n = [None, None, timestamp]\n        _n[0] = tail\n        _n[1] = self.dummy\n\n        self.size += 1\n\n    \"\"\"\n    @param: timestamp: An integer\n    @return: An integer\n    \"\"\"\n    def get_hit_count_in_last_5_minutes(self, timestamp):\n        head = self.dummy[1]\n\n        while (head is not self.dummy and\n               head[2] + 300 <= timestamp):\n            _, nxt, _ = head\n            self.dummy[1] = nxt\n            nxt[0] = self.dummy\n            head[0] = head[1] = None\n\n            head = nxt\n            self.size -= 1\n\n        return self.size\n"
  },
  {
    "path": "lintcode/509_mini_yelp.py",
    "content": "\"\"\"\nTest Case:\n\naddRestaurant(\"Lint Cafe\", 12.4999999, 11.599999)\naddRestaurant(\"Code Cafe\", 10.4999999, 11.512109)\nneighbors(10.5, 11.6, 6.7)\nremoveRestaurant(1)\naddRestaurant(\"Cafe2\", 11.4999999, 11.599999)\naddRestaurant(\"Cafe3\", 12.4999999, 11.512109)\nneighbors(10.5, 13.6, 8896.7)\nneighbors(8.5, 11.6, 6996.7)\naddRestaurant(\"Cafe4\", 11.4999999, 11.599999)\naddRestaurant(\"Cafe5\", 12.4999999, 78.512109)\nremoveRestaurant(3)\nneighbors(8.5, 70.6, 3200.7)\n: if `k` > the maximum error, return all hashcodes\n\"\"\"\n\n\"\"\"\nDefinition of Location:\nclass Location:\n    # @param {double} latitude, longitude\n    # @param {Location}\n    @classmethod\n    def create(cls, latitude, longitude):\n        # This will create a new location object\n\nDefinition of Restaurant:\nclass Restaurant:\n    # @param {str} name\n    # @param {Location} location\n    # @return {Restaurant}\n    @classmethod\n    def create(cls, name, location):\n        # This will create a new restaurant object,\n        # and auto fill id\n\nDefinition of Helper\nclass Helper:\n    # @param {Location} location1, location2\n    @classmethod\n    def get_distance(cls, location1, location2):\n        # return calculate the distance between two location\n\nDefinition of GeoHash\nclass GeoHash:\n    # @param {Location} location\n    # @return a string\n    @classmethom\n    def encode(cls, location):\n        # return convert location to a geohash string\n\n    # @param {str} hashcode\n    # @return {Location}\n    @classmethod\n    def decode(cls, hashcode):\n        # return convert a geohash string to location\n\"\"\"\n\n\"\"\"\nrange query from list by `bisect`\n\"\"\"\nimport bisect\nfrom YelpHelper import Location, Restaurant, GeoHash, Helper\n\n\nclass MiniYelp:\n    ERROR_IN_KM = (\n        2500, 630, 78,\n        20, 2.4, 0.61,\n        0.076, 0.01911, 0.00478,\n        0.0005971, 0.0001492, 0.0000186\n    )\n\n    restaurants = {}\n    restr_to_geohash = {}\n    geohashs = []\n\n    # @param {str} name\n    # @param {Location} location\n    # @return {int} restaurant's id\n    def add_restaurant(self, name, location):\n        restaurant = Restaurant.create(name, location)\n        hashcode = self.get_restr_hashcode(restaurant)\n\n        self.restaurants[hashcode] = restaurant\n        self.restr_to_geohash[restaurant.id] = hashcode\n        bisect.insort(self.geohashs, hashcode)\n\n        return restaurant.id\n\n    # @param {int} restaurant_id\n    # @return nothing\n    def remove_restaurant(self, restaurant_id):\n        hashcode = self.restr_to_geohash[restaurant_id]\n        index = bisect.bisect_left(self.geohashs, hashcode)\n\n        self.geohashs.pop(index)\n        del self.restaurants[hashcode]\n        del self.restr_to_geohash[restaurant_id]\n\n    # @param {Location} location\n    # @param {double} k, distance smaller than k miles\n    # @return {str[]} a list of restaurant's name and sort by\n    # distance from near to far.\n    def neighbors(self, location, k):\n        length = self.get_length(k)\n        prefix = GeoHash.encode(location)[:length]\n\n        # chr(ord('z') + 1) == '{'\n        left = bisect.bisect_left(self.geohashs, prefix)\n        right = bisect.bisect(self.geohashs, prefix + '{')\n\n        neighbors = []\n        hashcode = restaurant = distance = None\n        for i in range(left, right):\n            hashcode = self.geohashs[i]\n            restaurant = self.restaurants[hashcode]\n            distance = Helper.get_distance(location, restaurant.location)\n            if distance <= k:\n                neighbors.append((distance, restaurant))\n\n        neighbors.sort(key=lambda item: item[0])\n        return [\n            restr.name\n            for _, restr in neighbors\n        ]\n\n    def get_length(self, k):\n        n = len(self.ERROR_IN_KM)\n\n        for i in range(n):\n            if k > self.ERROR_IN_KM[i]:\n                return i\n\n        return n\n\n    def get_restr_hashcode(self, restaurant):\n        return '{0}:{1}'.format(\n            GeoHash.encode(restaurant.location),\n            restaurant.id\n        )\n\n\n\"\"\"\ntrie\n\"\"\"\nfrom YelpHelper import Location, Restaurant, GeoHash, Helper\n\n\nclass Trie:\n    def __init__(self):\n        self.root = self._new_node()\n\n    def __repr__(self):\n        return repr(self.root)\n\n    def put(self, key):\n        if not key:\n            return\n\n        parent = self.root\n        parent['keys'].add(key)\n        for char in key:\n            if char not in parent['children']:\n                parent['children'][char] = self._new_node()\n            parent['children'][char]['keys'].add(key)\n            parent = parent['children'][char]\n\n    def pick(self, key):\n        if not key:\n            return\n\n        parent = self.root\n        parent['keys'].discard(key)\n        for char in key:\n            if char not in parent['children']:\n                return\n            parent = parent['children'][char]\n            parent['keys'].discard(key)\n\n    def get_keys_by_prefix(self, prefix):\n        parent = self.root\n        if not prefix:\n            return list(parent['keys'])\n\n        for char in prefix:\n            if char not in parent['children']:\n                return []\n            parent = parent['children'][char]\n\n        return list(parent['keys'])\n\n    def _new_node(self):\n        return {\n            'keys': set(),\n            'children': {}\n        }\n\n\nclass MiniYelp:\n    ERROR_IN_KM = (\n        2500, 630, 78,\n        20, 2.4, 0.61,\n        0.076, 0.01911, 0.00478,\n        0.0005971, 0.0001492, 0.0000186\n    )\n\n    trie = Trie()\n    restaurants = {}\n    restr_to_geohash = {}\n\n    # @param {str} name\n    # @param {Location} location\n    # @return {int} restaurant's id\n    def add_restaurant(self, name, location):\n        restaurant = Restaurant.create(name, location)\n        hashcode = self.get_restr_hashcode(restaurant)\n\n        self.restaurants[hashcode] = restaurant\n        self.restr_to_geohash[restaurant.id] = hashcode\n        self.trie.put(hashcode)\n\n        return restaurant.id\n\n    # @param {int} restaurant_id\n    # @return nothing\n    def remove_restaurant(self, restaurant_id):\n        hashcode = self.restr_to_geohash[restaurant_id]\n\n        del self.restaurants[hashcode]\n        del self.restr_to_geohash[restaurant_id]\n        self.trie.pick(hashcode)\n\n    # @param {Location} location\n    # @param {double} k, distance smaller than k miles\n    # @return {str[]} a list of restaurant's name and sort by\n    # distance from near to far.\n    def neighbors(self, location, k):\n        length = self.get_length(k)\n        prefix = GeoHash.encode(location)[:length]\n        hashcodes = self.trie.get_keys_by_prefix(prefix)\n\n        neighbors = []\n        restaurant = distance = None\n        for hashcode in hashcodes:\n            restaurant = self.restaurants[hashcode]\n            distance = Helper.get_distance(location, restaurant.location)\n            if distance <= k:\n                neighbors.append((distance, restaurant))\n\n        neighbors.sort(key=lambda item: item[0])\n        return [\n            restr.name\n            for _, restr in neighbors\n        ]\n\n    def get_length(self, k):\n        n = len(self.ERROR_IN_KM)\n\n        for i in range(n):\n            if k > self.ERROR_IN_KM[i]:\n                return i\n\n        return n\n\n    def get_restr_hashcode(self, restaurant):\n        return '{0}:{1}'.format(\n            GeoHash.encode(restaurant.location),\n            restaurant.id\n        )\n"
  },
  {
    "path": "lintcode/510_maximal_rectangle.py",
    "content": "class Solution:\n    def maximalRectangle(self, G):\n        \"\"\"\n        :type G: List[List[str]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not G or not G[0]:\n            return ans\n\n        m, n = len(G), len(G[0])\n        L, R, H = {}, {}, {}\n\n        for i in range(m):\n            curr = 0  # left boundary\n            for j in range(n):\n                if G[i][j] == '1':\n                    H[j] = H.get(j, 0) + 1\n                    L[j] = max(L.get(j, 0), curr)\n                else:\n                    H[j] = L[j] = 0\n                    curr = j + 1\n\n            curr = n  # right boundary\n            for j in range(n - 1, -1, -1):\n                if G[i][j] == '1':\n                    R[j] = min(R.get(j, n), curr)\n                else:\n                    R[j] = n\n                    curr = j\n\n                ans = max(\n                    ans,\n                    H[j] * (R[j] - L[j])\n                )\n\n        return ans\n\n\n\"\"\"\nAssuming matrix: [\n  [1, 1, 0, 0, 1],\n  [0, 1, 0, 0, 1],\n  [0, 0, 1, 1, 1],\n  [0, 0, 1, 1, 1],\n  [0, 0, 0, 0, 1]\n]\n\nConcept:\nFor each (i, j), 0 <= i < len(mat), 0 <= j < len(mat[0])\nthe rectangle area is (r[j] - l[j]) * h[j]\n\nm = 0\nv 1 1 0 0 1\nh 1 1 0 0 1\nl 0 0 0 0 4\nr 2 2 5 5 5\n\nm = 1\nv 0 1 0 0 1\nh 0 2 0 0 2\nl 0 1 0 0 4\nr 5 2 5 5 5\n\nm = 2\nv 0 0 1 1 1\nh 0 0 1 1 3\nl 0 0 2 2 4\nr 5 5 5 5 5\n\nm = 3\nv 0 0 1 1 1\nh 0 0 2 2 4\nl 0 0 2 2 4\nr 5 5 5 5 5\n\nm = 4\nv 0 0 0 0 1\nh 0 0 0 0 5\nl 0 0 0 0 4\nr 5 5 5 5 5\n\nmax = 6 = (5 - 2) * 2\n\"\"\"\n\n\n# Mono Stack\n# This problem could be treated as histogram, see lintcode#122\nclass Solution:\n    def maximalRectangle(self, G):\n        \"\"\"\n        :type G: List[List[str]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not G or not G[0]:\n            return ans\n\n        m, n = len(G), len(G[0])\n        H = [0] * n\n\n        for i in range(m):\n            for j in range(n):\n                if G[i][j] == '1':\n                    H[j] += 1\n                else:\n                    H[j] = 0\n\n            ans = max(ans, self.largestRectangleArea(H))\n\n            # To remove the trick `0`\n            H.pop()\n\n        return ans\n\n    def largestRectangleArea(self, H):\n        area = 0\n        if not H:\n            return area\n\n        # To ensure the last element in monostack will be handled\n        H.append(0)\n\n        I = []\n        left = height = 0\n\n        for right in range(len(H)):\n            while I and H[I[-1]] >= H[right]:\n                height = H[I.pop()]\n                left = I[-1] if I else -1\n                area = max(\n                    area,\n                    height * (right - left - 1)\n                )\n            I.append(right)\n\n        return area\n"
  },
  {
    "path": "lintcode/512_decode_ways.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: a string,  encoded message\n    @return: an integer, the number of ways decoding\n    \"\"\"\n    def numDecodings(self, s):\n        if not s or s == '0':\n            return 0\n\n        n = len(s)\n\n        \"\"\"\n        `dp[i]` means the ways to decode\n\n        `dp[0]` => ''\n        `dp[1]` => should check if the code is 0\n        \"\"\"\n        dp = [0] * (n + 1)\n        dp[0] = 1\n        dp[1] = 0 if s[0] == '0' else 1\n\n        for i in range(2, n + 1):\n            if s[i - 1] != '0':\n                dp[i] += dp[i - 1]\n\n            if 10 <= int(s[i - 2:i]) <= 26:\n                dp[i] += dp[i - 2]\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/513_perfect_squares.py",
    "content": "\"\"\"\nTest Case:\n\n1\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: n: a positive integer\n    @return: An integer\n    \"\"\"\n    def numSquares(self, n):\n        if n <= 0:\n            return 0\n\n        INFINITY = float('inf')\n\n        # `dp[i]` means the least number of perfect square numbers of `i`\n        dp = [INFINITY] * (n + 1)\n        dp[0] = 0\n        dp[1] = 1\n\n        for i in range(1, n + 1):\n            j = 1\n            while j * j <= i:\n                dp[i] = min(dp[i], dp[i - j * j] + 1)\n                j += 1\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/515_paint_house.py",
    "content": "class Solution:\n    \"\"\"\n    @param: costs: n x 3 cost matrix\n    @return: An integer, the minimum cost to paint all houses\n    \"\"\"\n    def minCost(self, costs):\n        if not costs:\n            return 0\n\n        INFINITY = float('inf')\n        m, n = len(costs), len(costs[0])\n        dp = [[0] * n for _ in range(2)]\n\n        \"\"\"\n        i: `i`th house\n        j: `j`th color\n        k: the used `k`th color in previous house\n        \"\"\"\n        i = j = k = prev = curr = 0\n        for j in range(n):\n            dp[0][j] = costs[0][j]\n        for i in range(1, m):\n            prev = curr # (i - 1) % 2\n            curr = i % 2\n            for j in range(n):\n                dp[curr][j] = INFINITY\n                for k in range(n):\n                    if k != j and dp[prev][k] + costs[i][j] < dp[curr][j]:\n                        dp[curr][j] = dp[prev][k] + costs[i][j]\n\n        \"\"\"\n        curr == (m - 1) % 2\n        \"\"\"\n        return min(dp[curr])\n"
  },
  {
    "path": "lintcode/516_paint_house_ii.py",
    "content": "\"\"\"\nin `./lintcode/515_paint_house.py`\nwe repeatedly iterate `dp[prev]` to find the minimum except the same color\nbut in doing so, the time complexity is quite high `O(n * k * k)`,\nif the number of colors increases\n\nso in this problem, we need find some way to fix it\nfor `dp[curr][j] = dp[prev][k] + C[i][j]`, `C[i][j]` is constant\n\nso what we want is to find the minimum except the same color\n=> if `dp[prev][j]` is the minimum, since we can't use the same color\n   in adjacency houses, so we use the second minimum\n=> if not, we use the minimum\n\nand the time complexity becomes `O(n * 2k)` => `O(nk)`\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: C: n x k cost matrix\n    @return: an integer, the minimum cost to paint all houses\n    \"\"\"\n    def minCostII(self, C):\n        if not C or not C[0]:\n            return 0\n\n        INFINITY = float('inf')\n        n, k = len(C), len(C[0])\n        dp = [[0] * k for _ in range(n)]\n        prev = curr = 0\n\n        for j in range(k):\n            dp[curr][j] = C[0][j]\n\n        for i in range(1, n):\n            prev = curr\n            curr = 1 - curr\n            min1 = min2 = INFINITY\n\n            \"\"\"\n            to find the minimum and second minimum in previous iteration\n            \"\"\"\n            for j in range(k):\n                if dp[prev][j] < min1:\n                    min2 = min1\n                    min1 = dp[prev][j]\n                    continue\n                if dp[prev][j] < min2:\n                    min2 = dp[prev][j]\n\n            \"\"\"\n            if the `j`th color has been used, that is,\n            `dp[prev][j]` was the minimum, in previous iteration\n            and then we need to take the color\n            with the second minimum in `dp[prev]`\n            \"\"\"\n            for j in range(k):\n                dp[curr][j] = C[i][j]\n                if dp[prev][j] == min1:\n                    dp[curr][j] += min2\n                else:\n                    dp[curr][j] += min1\n\n        return min(dp[curr])\n"
  },
  {
    "path": "lintcode/517_ugly_number.py",
    "content": "class Solution:\n    def isUgly(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: bool\n        \"\"\"\n        if not num:\n            return False\n        if num == 1:\n            return True\n\n        for factor in (\n            125, 27, 8,\n            5, 3, 2,\n        ):\n            while num % factor == 0:\n                num //= factor\n\n            if num == 1:\n                return True\n\n        return num == 1\n"
  },
  {
    "path": "lintcode/518_super_ugly_number.py",
    "content": "class Solution:\n    def nthSuperUglyNumber(self, n, primes):\n        \"\"\"\n        :type n: int\n        :type primes: list[int]\n        :rtype: int\n        \"\"\"\n        if not n or n <= 1 or not primes:\n            return 1\n\n        k = len(primes)\n\n        # i -> same as `i` in `primes`, v -> track of how far `primes[i]` stay in `uglys`\n        steps = [0] * k\n        uglys = [0] * n\n        uglys[0] = 1\n\n        for i in range(1, n):\n            ugly = float('inf')\n\n            for j in range(k):\n                ugly = min(ugly, uglys[steps[j]] * primes[j])\n\n            uglys[i] = ugly\n\n            for j in range(k):\n                if uglys[steps[j]] * primes[j] == ugly:\n                    steps[j] += 1\n\n        return uglys[n - 1]\n"
  },
  {
    "path": "lintcode/519_consistent_hashing.py",
    "content": "class Solution:\n    \"\"\"\n    @param: n: a positive integer\n    @return: n x 3 matrix\n    \"\"\"\n    def consistentHashing(self, n):\n        res = [[0, 359, 1]]\n        if not isinstance(n, int) \\\n            or n < 2:\n            return res\n        ti = 0 # ti: target_index for the **upcoming** machine in results\n        # mi: machine_index for the **upcoming** machines in results\n        # for n is 5: got [1, 2, 3, 4]\n        for mi in range(1, n):\n            ti = 0\n            # emi: existing_machine_index for the **existing** machines in results\n            # for n is 5 and will add last machine: got [0, 1, 2, 3]\n            for emi in range(mi):\n                # Before adding each machine, check the current maximum partition\n                if res[emi][1] - res[emi][0] > res[ti][1] - res[ti][0]:\n                    ti = emi\n            x, y = res[ti][0], res[ti][1]\n            res[ti][1] = (x + y) / 2\n            res.append([(x + y) / 2 + 1, y, mi + 1])\n        return sorted(res, key=lambda item: item[0])\n"
  },
  {
    "path": "lintcode/51_previous_permutation.py",
    "content": "\"\"\"\nMain Concept:\n\n1. from end to start, finding first increasing element,\n   which is `nums[i]`\n2. from end to start, finding first element just smaller than `nums[i]`,\n   which is `nums[j]`.\n   and swap `nums[i]` and `nums[j]`.\n3. reverse the elements between `nums[i + 1]` and `nums[n - 1]`\n\nREF: [Next Permutation](https://leetcode.com/articles/next-permutation/)\n\"\"\"\n\n\nclass Solution:\n    def previousPermuation(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: list[int]\n        \"\"\"\n        if not nums or len(nums) < 2:\n            return nums\n\n        n = len(nums)\n        i = n - 2\n        while i >= 0 and nums[i] <= nums[i + 1]:\n            i -= 1\n\n        if i >= 0:\n            j = n - 1\n            while i < j and nums[i] <= nums[j]:\n                j -= 1\n            nums[i], nums[j] = nums[j], nums[i]\n\n        i = i + 1\n        j = n - 1\n        while i < j:\n            nums[i], nums[j] = nums[j], nums[i]\n            i += 1\n            j -= 1\n\n        return nums\n"
  },
  {
    "path": "lintcode/520_consistent_hashing_ii.py",
    "content": "import bisect\nimport random\n\nclass Solution:\n    \"\"\"\n    @param {int} n a positive integer\n    @param {int} k a positive integer\n    @return {Solution} a Solution object\n    \"\"\"\n    @classmethod\n    def create(cls, n, k):\n        solution = cls()\n        solution.n = n\n        solution.k = k\n        solution.p2l = {} # point to location\n        solution.l2p = {} # location to points\n        return solution\n\n    \"\"\"\n    @param: machine_id: An integer\n    @return: a list of shard ids\n    \"\"\"\n    def addMachine(self, machine_id):\n        item = self.l2p[machine_id] = []\n        point = -1\n        for i in range(self.k):\n            point = random.randint(0, self.n - 1)\n            while point in self.p2l:\n                point = random.randint(0, self.n - 1)\n            self.p2l[point] = machine_id\n            item.append(point)\n        item.sort()\n        return item\n\n    \"\"\"\n    @param: hashcode: An integer\n    @return: A machine id\n    \"\"\"\n    def getMachineIdByHashCode(self, hashcode):\n        points = sorted(self.p2l.keys())\n        index = bisect.bisect_left(points, hashcode) % len(points)\n        # # counterclockwise\n        # index = bisect.bisect(points, hashcode) - 1\n        # if index < 0:\n        #     index = len(points) - 1\n        return self.p2l[points[index]]\n"
  },
  {
    "path": "lintcode/521_remove_duplicate_numbers_in_array.py",
    "content": "\"\"\"\ntime: O(n)\nspace: O(n)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: nums: an array of integers\n    @return: the number of unique integers\n    \"\"\"\n    def deduplication(self, nums):\n        ans = 0\n        if not nums:\n            return ans\n\n        exists = set()\n        for i in range(len(nums)):\n            if nums[i] not in exists:\n                exists.add(nums[i])\n                ans += 1\n\n        return ans\n\n\n\"\"\"\ntime: O(nlogn)\nspace: O(1)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: nums: an array of integers\n    @return: the number of unique integers\n    \"\"\"\n    def deduplication(self, nums):\n        ans = 0\n        if not nums:\n            return ans\n\n        nums.sort()\n\n        # for `nums[0]`\n        ans = 1\n        for i in range(1, len(nums)):\n            if nums[i - 1] != nums[i]:\n                nums[ans] = nums[i]\n                ans += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/522_tiny_url_ii.py",
    "content": "import random\n\n\nclass TinyUrl2:\n    def __init__(self):\n        self.chars = [str(i) for i in range(10)]\n        self.chars.extend(chr(i) for i in range(ord('a'), ord('z') + 1))\n        self.chars.extend(chr(i) for i in range(ord('A'), ord('Z') + 1))\n\n        self.host = 'http://tiny.url/'\n        self.size = 6\n        self.lg2st = {}\n        self.st2lg = {}\n\n        self.custom_lg2st = {}\n        self.custom_st2lg = {}\n\n    def createCustom(self, url, key):\n        \"\"\"\n        :type url: str\n        :type key: str\n        :rtype: str\n        \"\"\"\n        if not url or not key:\n            return 'error'\n\n        if (\n            url in self.custom_lg2st and\n            key in self.custom_st2lg\n        ):\n            return self.get_tiny_url(key)\n\n        if (\n            url not in self.custom_lg2st and\n            key not in self.custom_st2lg\n        ):\n            self.custom_lg2st[url] = key\n            self.custom_st2lg[key] = url\n            return self.get_tiny_url(key)\n\n        return 'error'\n\n    def longToShort(self, url):\n        \"\"\"\n        :type url: str\n        :rtype: str\n        \"\"\"\n        if not url:\n            return 'error'\n        if url in self.lg2st:\n            return self.get_tiny_url(self.lg2st[url])\n        if url in self.custom_lg2st:\n            return self.get_tiny_url(self.custom_lg2st[url])\n\n        key = self.get_hash_key(self.size)\n        while key in self.st2lg:\n            key = self.get_hash_key(self.size)\n\n        self.lg2st[url] = key\n        self.st2lg[key] = url\n        return self.get_tiny_url(key)\n\n    def shortToLong(self, url):\n        \"\"\"\n        :type url: str\n        :rtype: str\n        \"\"\"\n        if not url:\n            return 'error'\n\n        key = url.replace(self.host, '')\n\n        if key in self.st2lg:\n            return self.st2lg[key]\n        if key in self.custom_st2lg:\n            return self.custom_st2lg[key]\n\n        return 'error'\n\n    def get_tiny_url(self, hash_key):\n        return '{}{}'.format(self.host, hash_key)\n\n    def get_hash_key(self, size):\n        return ''.join(\n            random.choice(self.chars)\n            for _ in range(size)\n        )\n"
  },
  {
    "path": "lintcode/523_url_parser.py",
    "content": "import re\n\nclass HtmlParser:\n    \"\"\"\n    @param: content: content source code\n    @return: a list of links\n    \"\"\"\n    def parseUrls(self, content):\n        # r'': use raw string\n        # [=\\s]+: this block should contain `=` or blank, and at least one char here\n        # [\"\\']: this block should contain `\"` or `'`\n        # [^\"\\'>\\s]*: this block should contain any chars until `\"`, `'`, `>`, or blank appears\n        links = re.findall(r'href[=\\s]+[\"\\']([^\"\\'>\\s]*)', content, re.I)\n        return [link for link in links if link and not link.startswith('#')]\n"
  },
  {
    "path": "lintcode/525_mini_uber.py",
    "content": "\"\"\"\nDefinition of Trip:\nclass Trip:\n    self.id; # trip's id, primary key\n    self.driver_id, self.rider_id; # foreign key\n    self.lat, self.lng; # pick up location\n    def __init__(self, rider_id, lat, lng):\n\nDefinition of Helper\nclass Helper:\n    @classmethod\n    def get_distance(cls, lat1, lng1, lat2, lng2):\n        # return calculate the distance between (lat1, lng1) and (lat2, lng2)\n\"\"\"\nfrom Trip import Trip, Helper\n\n\nclass MiniUber:\n    driver_to_locs = {}\n    driver_to_trip = {}\n    INFINITY = float('inf')\n\n    # @param {int} driver_id an integer\n    # @param {double} lat, lng driver's location\n    # return {trip} matched trip information\n    #               if there have matched rider or null\n    def report(self, driver_id, lat, lng):\n        if not driver_id:\n            return\n\n        if driver_id in self.driver_to_trip:\n            return self.driver_to_trip[driver_id]\n\n        if driver_id in self.driver_to_locs:\n            self.driver_to_locs[driver_id]['lat'] = lat\n            self.driver_to_locs[driver_id]['lng'] = lng\n        else:\n            self.driver_to_locs[driver_id] = self._new_location(lat, lng)\n\n    # @param rider_id an integer\n    # @param lat, lng rider's location\n    # return a trip\n    def request(self, rider_id, lat, lng):\n        if not rider_id:\n            return\n        trip = Trip(rider_id, lat, lng)\n        _distance = distance = self.INFINITY\n        driver_id = -1\n\n        for _driver_id, _loc in self.driver_to_locs.items():\n            _distance = Helper.get_distance(_loc['lat'], _loc['lng'], lat, lng)\n            if _distance < distance:\n                driver_id = _driver_id\n                distance = _distance\n\n        if driver_id == -1:\n            return trip\n\n        trip.driver_id = driver_id\n        self.driver_to_trip[driver_id] = trip\n        del self.driver_to_locs[driver_id]\n\n        return trip\n\n    def _new_location(self, lat, lng):\n        return {\n            'lat': lat,\n            'lng': lng\n        }\n"
  },
  {
    "path": "lintcode/526_load_balancer.py",
    "content": "import random\n\n\nclass LoadBalancer:\n    def __init__(self):\n        self.servers = []\n        self.svr2idx = {}\n\n    \"\"\"\n    @param: server_id: add a new server to the cluster\n    @return: nothing\n    \"\"\"\n    def add(self, server_id):\n        self.servers.append(server_id)\n        self.svr2idx[server_id] = len(self.servers) - 1\n\n    \"\"\"\n    @param: server_id: server_id remove a bad server from the cluster\n    @return: nothing\n    \"\"\"\n    def remove(self, server_id):\n        svrs = self.servers\n\n        i = self.svr2idx[server_id]\n        key = svrs[-1]\n\n        # swap `svrs[-1]` and `svrs[i]`\n        self.svr2idx[key] = i\n        svrs[i] = svrs[-1]\n\n        svrs.pop()\n        del self.svr2idx[server_id]\n\n    \"\"\"\n    @return: pick a server in the cluster randomly with equal probability\n    \"\"\"\n    def pick(self):\n        i = random.randrange(len(self.servers))\n        return self.servers[i]\n"
  },
  {
    "path": "lintcode/527_trie_serialization.py",
    "content": "\"\"\"\nDefinition of TrieNode:\nclass TrieNode:\n    def __init__(self):\n        # <key, value>: <Character, TrieNode>\n        self.children = collections.OrderedDict()\n\"\"\"\n\n\nclass Solution:\n\n    '''\n    @param root: An object of TrieNode, denote the root of the trie.\n    This method will be invoked first, you should design your own algorithm\n    to serialize a trie which denote by a root node to a string which\n    can be easily deserialized by your own \"deserialize\" method later.\n    '''\n    '''\n    For `<a<b<e<>>c<>d<f<>>>>`, the visual graph of the return data just like this:\n        <\n          a<\n            b<\n              e<>\n            >\n            c<>\n            d<\n              f<>\n            >\n          >\n        >\n    '''\n    def serialize(self, root):\n        if not root:\n            return ''\n        data = ''\n        for key, node in root.children.items():\n            data += key + self.serialize(node)\n        return '<%s>' % data\n\n    '''\n    @param data: A string serialized by your serialize method.\n    This method will be invoked second, the argument data is what exactly\n    you serialized at method \"serialize\", that means the data is not given by\n    system, it's given by your own serialize method. So the format of data is\n    designed by yourself, and deserialize it here as you serialize it in\n    \"serialize\" method.\n    '''\n    def deserialize(self, data):\n        if not data \\\n                or data[0] != '<' \\\n                or data[-1] != '>' \\\n                or len(data) < 1:\n            return\n        root = TrieNode()\n        current = root\n        queue = []\n        for char in data:\n            if char == '<':\n                queue.append(current)\n            elif char == '>':\n                queue.pop()\n            else:\n                current = TrieNode()\n                queue[-1].children[char] = current\n        return root\n"
  },
  {
    "path": "lintcode/528_flatten_nested_list_iterator.py",
    "content": "\"\"\"\nYour NestedIterator object will be instantiated and called as such:\ni, v = NestedIterator(nestedList), []\nwhile i.hasNext(): v.append(i.next())\n\n\nThis is the interface that allows for creating nested lists.\nYou should not implement it, or speculate about its implementation\n\nclass NestedInteger(object):\n    def isInteger(self):\n        # @return {boolean} True if this NestedInteger holds a single integer,\n        # rather than a nested list.\n\n    def getInteger(self):\n        # @return {int} the single integer that this NestedInteger holds,\n        # if it holds a single integer\n        # Return None if this NestedInteger holds a nested list\n\n    def getList(self):\n        # @return {NestedInteger[]} the nested list that this NestedInteger holds,\n        # if it holds a nested list\n        # Return None if this NestedInteger holds a single integer\n\"\"\"\n\n\nclass NestedIterator(object):\n    def __init__(self, nestedList):\n        self.stack = [[nestedList, 0]]\n\n    # @return {int} the next element in the iteration\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        lst, i = self.stack[-1]\n        self.stack[-1][1] += 1\n\n        return lst[i].getInteger()\n\n    # @return {boolean} true if the iteration has more element or false\n    def hasNext(self):\n        stack = self.stack\n\n        while stack:\n            lst, i = stack[-1]\n\n            if i >= len(lst):\n                stack.pop()\n            elif lst[i].isInteger():\n                return True\n            else:\n                # lst[i] is list\n                stack[-1][1] += 1\n                stack.append([lst[i].getList(), 0])\n\n        return False\n"
  },
  {
    "path": "lintcode/529_geohash.py",
    "content": "\"\"\"\nmain concept is in `../module/geohash.py`\n\"\"\"\n\n\nclass GeoHash:\n    base32 = []\n\n    \"\"\"\n    @param: latitude: one of a location coordinate pair\n    @param: longitude: one of a location coordinate pair\n    @param: precision: an integer between 1 to 12\n    @return: a base32 string\n    \"\"\"\n    def encode(self, latitude, longitude, precision=5):\n        if not self.base32:\n            self.base32 = self.get_base32_list()\n\n        times = (precision * 5) // 2 + 1\n        lat_codes = self._loc_to_bins( latitude, times,  -90,  90)\n        lng_codes = self._loc_to_bins(longitude, times, -180, 180)\n\n        bin_codes = []\n        for i in range(times):\n            bin_codes.extend((str(lng_codes[i]), str(lat_codes[i])))\n\n        hash_codes = []\n        hash_code = ''\n        for i in range(0, len(bin_codes), 5):\n            hash_code = int(''.join(bin_codes[i : i + 5]), 2)\n            hash_codes.append(self.base32[hash_code])\n\n        return ''.join(hash_codes[:precision])\n\n    def _loc_to_bins(self, location, times, left, right):\n        mid = 0\n        bins = []\n\n        for i in range(times):\n            mid = left + (right - left) / 2.0\n            if location > mid:\n                left = mid\n                bins.append(1)\n            else:\n                right = mid\n                bins.append(0)\n\n        return bins\n\n    def get_base32_list(self):\n        base32_list = [str(i) for i in range(10)]\n\n        ignored_char = (ord('a'), ord('i'), ord('l'), ord('o'))\n        for i in range(ord('a'), ord('z') + 1):\n            if i in ignored_char:\n                continue\n            base32_list.append(chr(i))\n\n        return base32_list\n"
  },
  {
    "path": "lintcode/52_next_permutation.py",
    "content": "\"\"\"\nMain Concept:\n\n1. from end to start, finding first decreasing element,\n   which is `nums[i]`\n2. from end to start, finding first element just larger than `nums[i]`,\n   which is `nums[j]`.\n   and swap `nums[i]` and `nums[j]`.\n3. reverse the elements between `nums[i + 1]` and `nums[n - 1]`\n\nREF: [Next Permutation](https://leetcode.com/articles/next-permutation/)\n\"\"\"\n\n\nclass Solution:\n    def nextPermutation(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: list[int]\n        \"\"\"\n        if not nums or len(nums) < 2:\n            return nums\n\n        n = len(nums)\n        i = n - 2\n        while i >= 0 and nums[i] >= nums[i + 1]:\n            i -= 1\n\n        if i >= 0:\n            j = n - 1\n            while i < j and nums[i] >= nums[j]:\n                j -= 1\n            nums[i], nums[j] = nums[j], nums[i]\n\n        i = i + 1\n        j = n - 1\n        while i < j:\n            nums[i], nums[j] = nums[j], nums[i]\n            i += 1\n            j -= 1\n\n        return nums\n"
  },
  {
    "path": "lintcode/530_geohash_ii.py",
    "content": "\"\"\"\nmain concept is in `../module/geohash.py`\n\"\"\"\n\n\nclass GeoHash:\n    base32 = []\n\n    \"\"\"\n    @param: geohash: geohash a base32 string\n    @return: latitude and longitude a location coordinate pair\n    \"\"\"\n    def decode(self, geohash):\n        if not geohash:\n            return []\n        if not self.base32:\n            self.base32 = self.get_base32_list()\n\n        bin_codes = []\n        for char in geohash:\n            if char not in self.base32:\n                return []\n            bin_codes.extend(self._oct_to_bins(self.base32.index(char)))\n\n        n = len(bin_codes)\n        lat_codes = [bin_codes[i] for i in range(1, n, 2)]\n        lng_codes = [bin_codes[i] for i in range(0, n, 2)]\n\n        return [\n            self._bins_to_loc(lat_codes,  -90,  90),\n            self._bins_to_loc(lng_codes, -180, 180)\n        ]\n\n    def _bins_to_loc(self, bins, left, right):\n        mid = 0\n\n        for code in bins:\n            mid = left + (right - left) / 2.0\n            if code:\n                left = mid\n            else:\n                right = mid\n\n        return left + (right - left) / 2.0\n\n    def _oct_to_bins(self, val_in_oct):\n        bins = []\n        for i in range(5):\n            if val_in_oct % 2:\n                bins.append(1)\n            else:\n                bins.append(0)\n            val_in_oct = val_in_oct >> 1\n\n        return reversed(bins)\n\n    def get_base32_list(self):\n        base32_list = [str(i) for i in range(10)]\n\n        ignored_char = (ord('a'), ord('i'), ord('l'), ord('o'))\n        for i in range(ord('a'), ord('z') + 1):\n            if i in ignored_char:\n                continue\n            base32_list.append(chr(i))\n\n        return base32_list\n"
  },
  {
    "path": "lintcode/531_six_degrees.py",
    "content": "\"\"\"\nDefinition for Undirected graph node\nclass UndirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: graph: a list of Undirected graph node\n    @param: s: Undirected graph node\n    @param: t: Undirected graph nodes\n    @return: an integer\n    \"\"\"\n    def sixDegrees(self, graph, s, t):\n        if not graph or not s or not t:\n            return -1\n        if s is t:\n            return 0\n\n        degree = {s: 0}\n        queue = [s]\n        for node in queue:\n            for _node in node.neighbors:\n                if _node in degree:\n                    continue\n                degree[_node] = degree[node] + 1\n                if _node is t:\n                    return degree[_node]\n                queue.append(_node)\n\n        return -1\n"
  },
  {
    "path": "lintcode/532_reverse_pairs.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an array\n    @return: total of reverse pairs\n    \"\"\"\n    def reversePairs(self, A):\n        n = len(A)\n        tmp = [0] * n\n        return self.merge_sort(A, 0, n - 1, tmp)\n\n    def merge_sort(self, A, start, end, tmp):\n        if start >= end:\n            return 0\n\n        mid = (start + end) // 2\n        left, right = start, mid + 1\n        ans = self.merge_sort(A, left, mid, tmp)\n        ans += self.merge_sort(A, right, end, tmp)\n\n        i = start\n        while left <= mid and right <= end:\n            if A[left] > A[right]:\n                tmp[i] = A[right]\n                right += 1\n                ans += mid - left + 1\n            else:\n                tmp[i] = A[left]\n                left += 1\n            i += 1\n\n        while left <= mid:\n            tmp[i] = A[left]\n            left += 1\n            i += 1\n\n        while right <= end:\n            tmp[i] = A[right]\n            right += 1\n            i += 1\n\n        for i in range(start, end + 1):\n            A[i] = tmp[i]\n\n        return ans\n"
  },
  {
    "path": "lintcode/533_two_sum_closest_to_target.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: an integer array\n    @param: target: An integer\n    @return: the difference between the sum and the target\n    \"\"\"\n    def twoSumClosest(self, nums, target):\n        if not nums or len(nums) < 2:\n            return -1\n\n        nums.sort()\n\n        left, right = 0, len(nums) - 1\n        _sum = 0\n        diff = float('inf')\n        while left < right:\n            _sum = nums[left] + nums[right]\n            if _sum < target:\n                diff = min(diff, target - _sum)\n                left += 1\n            else:\n                diff = min(diff, _sum - target)\n                right -= 1\n\n        return diff\n"
  },
  {
    "path": "lintcode/534_house_robber_ii.py",
    "content": "\"\"\"\nMain Concept:\n\nif we insist on not stealing one of the houses\n=> the remaining houses become a sequence\n=> the problem becomes `./lintcode/392_house_robber.py`\n\nwe can pick any pair of adjacent houses,\nand to make the calculation easier,\nwe pick the first and last houses\n\n1. insist on not stealing the first house\n   that is, the range becomes `[1, n - 1]`\n2. insist on not stealing the last house\n   that is, the range becomes `[0, n - 2]`\n\nand choose the maximum amount as the answer\n\n\nTest Case:\n\n[3,6,4]\n\n[1,3,2,1,5]\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of non-negative integers.\n    @return: The maximum amount of money you can rob tonight\n    \"\"\"\n    def houseRobber2(self, A):\n        if not A:\n            return 0\n        if len(A) == 1:\n            return A[0]\n\n        dp = [[0] * 2 for _ in range(2)]\n\n        return max(\n            self.houseRobber(A, 0, dp),\n            self.houseRobber(A, 1, dp)\n        )\n\n    def houseRobber(self, A, start, dp):\n        n = len(A)\n        prev, curr = 0, start % 2\n        dp[curr][0] = 0\n        dp[curr][1] = A[start]\n\n        for i in range(1 + start, n - 1 + start):\n            prev = curr\n            curr = i % 2\n\n            dp[curr][0] = max(dp[prev])\n            dp[curr][1] = dp[prev][0] + A[i]\n\n        return max(dp[curr])\n\n\nclass Solution:\n    \"\"\"\n    @param: A: An array of non-negative integers.\n    @return: The maximum amount of money you can rob tonight\n    \"\"\"\n    def houseRobber2(self, A):\n        if not A:\n            return 0\n\n        n = len(A)\n        if n == 1:\n            return A[0]\n        if n == 2:\n            return max(A[0], A[1])\n\n        dp = [0] * 3\n\n        return max(\n            # range(0, n - 1)\n            self.houseRobber(A, 0, dp),\n            # range(1, n)\n            self.houseRobber(A, 1, dp)\n        )\n\n    def houseRobber(self, A, start, dp):\n        n = len(A)\n        prev2, prev1, curr = 0, start % 3, (start + 1) % 3\n        dp[prev1] = A[start]\n        dp[curr] = max(A[start], A[start + 1])\n\n        for i in range(2 + start, n - 1 + start):\n            prev2, prev1 = prev1, curr\n            curr = i % 3\n\n            dp[curr] = max(dp[prev1], dp[prev2] + A[i])\n\n        return dp[curr]\n\n\nclass Solution:\n    def houseRobber2(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        if not A:\n            return 0\n        n = len(A)\n        if n < 2:\n            return A[0]\n\n        return max(\n            self.rob_in_line(A, 0, n - 2),\n            self.rob_in_line(A, 1, n - 1)\n        )\n\n    def rob_in_line(self, A, start, end):\n        n = end - start + 1\n        dp = [0] * (n + 1)\n        dp[0] = 0\n        dp[1] = A[start]\n\n        for i in range(2, n + 1):\n            dp[i] = max(\n                dp[i - 2] + A[start + i - 1],\n                dp[i - 1]\n            )\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/538_memcache.py",
    "content": "class Memcache:\n\n    INT_MAX = 0x7FFFFFFF\n    PERMANENT_TTL = -1\n    storage = {}\n\n    \"\"\"\n    @param: curtTime: An integer\n    @param: key: An integer\n    @return: An integer\n    \"\"\"\n    def get(self, curtTime, key):\n        if key not in self.storage:\n            return self.INT_MAX\n\n        if (curtTime < self.storage[key]['expired_at'] or\n            self.storage[key]['expired_at'] == self.PERMANENT_TTL):\n            return self.storage[key]['val']\n\n        return self.INT_MAX\n\n    \"\"\"\n    @param: curtTime: An integer\n    @param: key: An integer\n    @param: value: An integer\n    @param: ttl: An integer\n    @return: nothing\n    \"\"\"\n    def set(self, curtTime, key, value, ttl):\n        if ttl > 0:\n            self.storage[key] = self._new_item(key, value, curtTime + ttl)\n        else:\n            self.storage[key] = self._new_item(key, value, self.PERMANENT_TTL)\n\n    \"\"\"\n    @param: curtTime: An integer\n    @param: key: An integer\n    @return: nothing\n    \"\"\"\n    def delete(self, curtTime, key):\n        if key in self.storage:\n            del self.storage[key]\n\n    \"\"\"\n    @param: curtTime: An integer\n    @param: key: An integer\n    @param: delta: An integer\n    @return: An integer\n    \"\"\"\n    def incr(self, curtTime, key, delta):\n        if key not in self.storage:\n            return self.INT_MAX\n\n        if (curtTime < self.storage[key]['expired_at'] or\n            self.storage[key]['expired_at'] == self.PERMANENT_TTL):\n            self.storage[key]['val'] += delta\n            return self.storage[key]['val']\n\n        return self.INT_MAX\n\n    \"\"\"\n    @param: curtTime: An integer\n    @param: key: An integer\n    @param: delta: An integer\n    @return: An integer\n    \"\"\"\n    def decr(self, curtTime, key, delta):\n        return self.incr(curtTime, key, -1 * delta)\n\n    def _new_item(self, key, value, expired_at):\n        return {\n            'key': key,\n            'val': value,\n            'expired_at': expired_at\n        }\n"
  },
  {
    "path": "lintcode/539_move_zeroes.py",
    "content": "class Solution:\n    def moveZeroes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        if not nums:\n            return\n\n        n = len(nums)\n        left = 0\n\n        for right in range(n):\n            if nums[right] != 0:\n                nums[left], nums[right] = nums[right], nums[left]\n                left += 1\n"
  },
  {
    "path": "lintcode/53_reverse_words_in_a_string.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: A string\n    @return: A string\n    \"\"\"\n    def reverseWords(self, s):\n        s = s.strip()\n        if not s:\n            return ''\n\n        return ' '.join(reversed(s.split()))\n"
  },
  {
    "path": "lintcode/540_zigzag_iterator.py",
    "content": "\"\"\"\nYour ZigzagIterator object will be instantiated and called as such:\nsolution, result = ZigzagIterator(v1, v2), []\nwhile solution.hasNext(): result.append(solution.next())\nOutput result\n\"\"\"\n\n\nclass ZigzagIterator:\n    \"\"\"\n    @param: v1: A 1d vector\n    @param: v2: A 1d vector\n    \"\"\"\n    def __init__(self, v1, v2):\n        self.g = (v1, v2)\n        self.x = 0\n        self.y = 0\n        self.max_y = max(len(vec) for vec in self.g)\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        x = self.x\n        y = self.y\n\n        self.x += 1\n\n        return self.g[x][y]\n\n    \"\"\"\n    @return: True if has next\n    \"\"\"\n    def hasNext(self):\n        while self.y < self.max_y:\n            if (\n                self.x < len(self.g) and\n                self.y < len(self.g[self.x])\n            ):\n                return True\n\n            if self.x >= len(self.g):\n                self.x = 0\n                self.y += 1\n\n            if self.y >= len(self.g[self.x]):\n                self.x += 1\n\n        return False\n\n\nclass ZigzagIterator:\n    \"\"\"\n    @param: v1: A 1d vector\n    @param: v2: A 1d vector\n    \"\"\"\n    def __init__(self, v1, v2):\n        self.queue = [vec for vec in (v1, v2) if vec]\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        vec = self.queue.pop(0)\n        val = vec.pop(0)\n\n        if vec:\n            self.queue.append(vec)\n\n        return val\n\n    \"\"\"\n    @return: True if has next\n    \"\"\"\n    def hasNext(self):\n        return bool(self.queue)\n"
  },
  {
    "path": "lintcode/541_zigzag_iterator_ii.py",
    "content": "\"\"\"\nYour ZigzagIterator2 object will be instantiated and called as such:\nsolution, result = ZigzagIterator2(vecs), []\nwhile solution.hasNext(): result.append(solution.next())\nOutput result\n\"\"\"\n\n\nclass ZigzagIterator2:\n    \"\"\"\n    @param: vecs: a list of 1d vectors\n    \"\"\"\n    def __init__(self, vecs):\n        self.g = vecs\n        self.x = 0\n        self.y = 0\n        self.max_y = max(len(vec) for vec in vecs)\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        x = self.x\n        y = self.y\n\n        self.x += 1\n\n        return self.g[x][y]\n\n    \"\"\"\n    @return: True if has next\n    \"\"\"\n    def hasNext(self):\n        while self.y < self.max_y:\n            if (\n                self.x < len(self.g) and\n                self.y < len(self.g[self.x])\n            ):\n                return True\n\n            if self.x >= len(self.g):\n                self.x = 0\n                self.y += 1\n\n            if self.y >= len(self.g[self.x]):\n                self.x += 1\n\n        return False\n\n\nclass ZigzagIterator2:\n    \"\"\"\n    @param: vecs: a list of 1d vectors\n    \"\"\"\n    def __init__(self, vecs):\n        self.queue = [vec for vec in vecs if vec]\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        vec = self.queue.pop(0)\n        val = vec.pop(0)\n\n        if vec:\n            self.queue.append(vec)\n\n        return val\n\n    \"\"\"\n    @return: True if has next\n    \"\"\"\n    def hasNext(self):\n        return bool(self.queue)\n"
  },
  {
    "path": "lintcode/543_kth_largest_in_n_arrays.py",
    "content": "import heapq\n\nclass Solution:\n\n    \"\"\"\n    @param: arrays: a list of array\n    @param: k: An integer\n    @return: an integer, K-th largest element in N arrays\n    \"\"\"\n    def KthInArrays(self, arrays, k):\n        res = []\n        for arr in arrays: res += arr\n        if k > len(res):\n            return 'error'\n        res.sort()\n        return res[-k]\n"
  },
  {
    "path": "lintcode/544_top_k_largest_numbers.py",
    "content": "from heapq import heappush, heappop\n\n\nclass Solution:\n    \"\"\"\n    @param: nums: an integer array\n    @param: k: An integer\n    @return: the top k largest numbers in array\n    \"\"\"\n    def topk(self, nums, k):\n        \"\"\"\n        min heap (normal case in heapq, max heap needs to times -1)\n        \"\"\"\n        if not nums:\n            return\n\n        ans = []\n        for num in nums:\n            heappush(ans, num)\n\n            if len(ans) > k:\n                heappop(ans)\n\n        ans.sort(reverse=True)\n\n        return ans\n"
  },
  {
    "path": "lintcode/545_top_k_largest_numbers_ii.py",
    "content": "from heapq import heappop, heappush\n\n\nclass Solution:\n    \"\"\"\n    @param: k: An integer\n    \"\"\"\n    def __init__(self, k):\n        self.k = k\n        self.tops = []\n\n    \"\"\"\n    @param: num: Number to be added\n    @return: nothing\n    \"\"\"\n    def add(self, num):\n        # push in first, since we cannot ensure\n        # the incoming num will stay in tops\n        heappush(self.tops, num)\n\n        if len(self.tops) > self.k:\n            heappop(self.tops)\n\n    \"\"\"\n    @return: Top k element\n    \"\"\"\n    def topk(self):\n        return sorted(self.tops, reverse=True)\n"
  },
  {
    "path": "lintcode/547_intersection_of_two_arrays.py",
    "content": "class Solution:\n    def intersection(self, a, b):\n        \"\"\"\n        :type a: List[int]\n        :type b: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not a or not b:\n            return ans\n\n        s = set(a)\n        t = set(b)\n\n        for x in s:\n            if x in t:\n                ans.append(x)\n\n        return ans\n\n\nclass Solution:\n    def intersection(self, a, b):\n        \"\"\"\n        :type a: List[int]\n        :type b: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not a or not b:\n            return ans\n\n        a.sort()\n        b.sort()\n\n        m, n = len(a), len(b)\n        i = j = 0\n\n        while i < m and j < n:\n            if a[i] == b[j]:\n                if not ans or a[i] != ans[-1]:\n                    ans.append(a[i])\n                i += 1\n                j += 1\n            elif a[i] < b[j]:\n                i += 1\n            else:\n                j += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/548_intersection_of_two_arrays_ii.py",
    "content": "class Solution:\n    def intersect(self, a, b):\n        \"\"\"\n        :type a: List[int]\n        :type b: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not a or not b:\n            return ans\n\n        freq = {}\n\n        for x in a:\n            freq[x] = freq.get(x, 0) + 1\n\n        for x in b:\n            if not freq.get(x):\n                continue\n\n            freq[x] -= 1\n            ans.append(x)\n\n        return ans\n\n\nclass Solution:\n    def intersect(self, a, b):\n        \"\"\"\n        :type a: List[int]\n        :type b: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n\n        if not a or not b:\n            return ans\n\n        a.sort()\n        b.sort()\n\n        m, n = len(a), len(b)\n        i = j = 0\n\n        while i < m and j < n:\n            if a[i] == b[j]:\n                ans.append(a[i])\n                i += 1\n                j += 1\n            elif a[i] < b[j]:\n                i += 1\n            else:\n                j += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/54_string_to_integer_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: A string\n    @return: An integer\n    \"\"\"\n    def atoi(self, s):\n        NOT_FOUND = 0\n        if not s:\n            return NOT_FOUND\n\n        n = len(s)\n        is_negative = False\n        left, right = 0, n - 1\n\n        while left < n and s[left] == ' ':\n            left += 1\n        while right >= 0 and s[right] == ' ':\n            right -= 1\n\n        if left < n and s[left] in ('+', '-'):\n            is_negative = (s[left] == '-')\n            left += 1\n\n        if left > right:\n            return NOT_FOUND\n\n        ans = 0\n        zero = ord('0')\n        nine = ord('9')\n        INT_MAX = 0x7FFFFFFF\n        INT_MIN = -0x80000000\n        while left <= right and zero <= ord(s[left]) <= nine:\n            ans = ans * 10 + ord(s[left]) - zero\n            left += 1\n\n        if is_negative:\n            ans *= -1\n\n        if ans > INT_MAX:\n            return INT_MAX\n        if ans < INT_MIN:\n            return INT_MIN\n\n        return ans\n"
  },
  {
    "path": "lintcode/551_nested_list_weight_sum.py",
    "content": "\"\"\"\nThis is the interface that allows for creating nested lists.\nYou should not implement it, or speculate about its implementation\n\nclass NestedInteger(object):\n    def isInteger(self):\n        # @return {boolean} True if this NestedInteger holds a single integer,\n        # rather than a nested list.\n\n    def getInteger(self):\n        # @return {int} the single integer that this NestedInteger holds,\n        # if it holds a single integer\n        # Return None if this NestedInteger holds a nested list\n\n    def getList(self):\n        # @return {NestedInteger[]} the nested list that this NestedInteger holds,\n        # if it holds a nested list\n        # Return None if this NestedInteger holds a single integer\n\"\"\"\n\n\nclass Solution(object):\n    # @param {NestedInteger[]} L a list of NestedInteger Object\n    # @return {int} an integer\n    def depthSum(self, L):\n        return self.dfs(L, 1)\n\n    def dfs(self, L, depth):\n        _sum = 0\n\n        for obj in L:\n            if obj.isInteger():\n                _sum += depth * obj.getInteger()\n                continue\n\n            _sum += self.dfs(obj.getList(), depth + 1)\n\n        return _sum\n\n\nclass Solution(object):\n    # @param {NestedInteger[]} L a list of NestedInteger Object\n    # @return {int} an integer\n    def depthSum(self, L):\n        ans = 0\n        if not L:\n            return ans\n\n        queue = L\n        depth = 0\n        while queue:\n            _queue = []\n            depth += 1\n\n            for obj in queue:\n                if obj.isInteger():\n                    ans += depth * obj.getInteger()\n                    continue\n\n                _queue.extend(obj.getList())\n\n            queue = _queue\n\n        return ans\n"
  },
  {
    "path": "lintcode/552_create_maximum_number.py",
    "content": "class Solution:\n    def maxNumber(self, a, b, k):\n        \"\"\"\n        :type a: list[int]\n        :type b: list[int]\n        :type k: int, k <= m + n\n        :rtype: list[int]\n        \"\"\"\n        ans = []\n\n        for size in range(\n            max(0, k - len(a)),\n            min(k, len(b)) + 1\n        ):\n            res = self.merge(\n                self.get_max(a, k - size),\n                self.get_max(b, size)\n            )\n            ans = max(ans, res)\n\n        return ans\n\n    def get_max(self, a, size):\n        res = []\n        n = len(a)\n\n        for i in range(n):\n            while (\n                res and\n                len(res) + n - i > size and\n                res[-1] < a[i]\n            ):\n                res.pop()\n\n            if len(res) < size:\n                res.append(a[i])\n\n        return res\n\n    def merge(self, a, b):\n        return [\n            max(a, b).pop(0)\n            for _ in range(len(a) + len(b))\n        ]\n"
  },
  {
    "path": "lintcode/553_bomb_enemy.py",
    "content": "\"\"\"\nCache sharing nodes\n\nMain Concept:\n\n1. the number of enemies killed is same between the two walls in line\n\n        y\n        0 1 2 3 4\n    x 0   W\n      1 k 0 k W l\n      2   n\n      3   W\n      4   m\n\n    the number of enemies killed is `n + k` at (1, 1)\n\n2. since the iteration order, we can optimize\n   the space complexity in row\n\n    x  y   0    1    2    3\n    0 [[ | 0, | E, | 0, | 0 ],  --1-->\n    1  [ | E, | 0, v W, | E ],  --2-->\n    2  [ v 0, v E, v 0, v 0 ]]  --3-->\n\"\"\"\n\n\nclass Solution:\n    WALL = 'W'\n    ENEMY = 'E'\n    EMPTY = '0'\n\n    def maxKilledEnemies(self, grid):\n        \"\"\"\n        :type grid: list[list[str]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not grid or not grid[0]:\n            return ans\n\n        m, n = len(grid), len(grid[0])\n        row, cols = 0, [0] * n\n\n        for x in range(m):\n            for y in range(n):\n                # calculate bomb in cur section [x, 'WALL' | m) in col\n                if x == 0 or grid[x - 1][y] == self.WALL:\n                    cols[y] = 0\n\n                    for i in range(x, m):\n                        if grid[i][y] == self.WALL:\n                            break\n                        if grid[i][y] == self.ENEMY:\n                            cols[y] += 1\n\n                # calculate bomb in cur section [y, 'WALL' | n) in row\n                if y == 0 or grid[x][y - 1] == self.WALL:\n                    row = 0\n\n                    for i in range(y, n):\n                        if grid[x][i] == self.WALL:\n                            break\n                        if grid[x][i] == self.ENEMY:\n                            row += 1\n\n                if grid[x][y] == self.EMPTY and row + cols[y] > ans:\n                    ans = row + cols[y]\n\n        return ans\n\n\n\"\"\"\nTLE\ntime: O(m^2 * n^2)\n\"\"\"\nclass Solution:\n    WALL = 'W'\n    ENEMY = 'E'\n    EMPTY = '0'\n\n    def maxKilledEnemies(self, grid):\n        \"\"\"\n        :type grid: list[list[str]]\n        :rtype: int\n        \"\"\"\n        ans = 0\n        if not grid or not grid[0]:\n            return ans\n\n        for x in range(len(grid)):\n            for y in range(len(grid[0])):\n                if grid[x][y] == self.EMPTY:\n                    ans = max(\n                        ans,\n                        self.get_killed_cnt(grid, x, y)\n                    )\n\n        return ans\n\n    def get_killed_cnt(self, grid, i, j):\n        m, n = len(grid), len(grid[0])\n        cnt = 0\n\n        # up\n        for x in range(i, -1, -1):\n            if grid[x][j] == self.WALL:\n                break\n            if grid[x][j] == self.ENEMY:\n                cnt += 1\n\n        # down\n        for x in range(i, m):\n            if grid[x][j] == self.WALL:\n                break\n            if grid[x][j] == self.ENEMY:\n                cnt += 1\n\n        # left\n        for y in range(j, -1, -1):\n            if grid[i][y] == self.WALL:\n                break\n            if grid[i][y] == self.ENEMY:\n                cnt += 1\n\n        # right\n        for y in range(j, n):\n            if grid[i][y] == self.WALL:\n                break\n            if grid[i][y] == self.ENEMY:\n                cnt += 1\n\n        return cnt\n"
  },
  {
    "path": "lintcode/555_counting_bloom_filter.py",
    "content": "from random import randint\n\n\nclass HashFunc:\n    def __init__(self, cap, seed):\n        self.cap = cap\n        self.seed = seed\n\n    def hash(self, key):\n        code = 0\n        if not key:\n            return code\n\n        for char in key:\n            code = (self.seed * code + ord(char)) % self.cap\n\n        return code\n\n\nclass CountingBloomFilter:\n    def __init__(self, k):\n        \"\"\"\n        :type k: int\n        \"\"\"\n        CAP = 20000\n\n        self.bits = [0] * CAP\n        self.hashs = []\n\n        for i in range(k):\n            self.hashs.append(HashFunc(\n                randint(CAP // 2, CAP),\n                i * 2 + 3\n            ))\n\n    def add(self, word):\n        \"\"\"\n        :type word: str\n        :rtype: None\n        \"\"\"\n        for f in self.hashs:\n            index = f.hash(word)\n            self.bits[index] += 1\n\n    def remove(self, word):\n        \"\"\"\n        :type word: str\n        :rtype: None\n        \"\"\"\n        for f in self.hashs:\n            index = f.hash(word)\n            self.bits[index] -= 1\n\n    def contains(self, word):\n        \"\"\"\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        for f in self.hashs:\n            index = f.hash(word)\n            if self.bits[index] <= 0:\n                return False\n        return True\n"
  },
  {
    "path": "lintcode/556_standard_bloom_filter.py",
    "content": "from random import randint\n\n\nclass HashFunc:\n    def __init__(self, cap, seed):\n        self.cap = cap\n        self.seed = seed\n\n    def hash(self, key):\n        code = 0\n        if not key:\n            return code\n\n        for char in key:\n            code = (self.seed * code + ord(char)) % self.cap\n\n        return code\n\n\nclass StandardBloomFilter:\n    def __init__(self, k):\n        \"\"\"\n        :type k: int\n        \"\"\"\n        CAP = 20000\n\n        self.bits = [0] * CAP\n        self.hashs = []\n\n        for i in range(k):\n            self.hashs.append(HashFunc(\n                randint(CAP // 2, CAP),\n                i * 2 + 3\n            ))\n\n    def add(self, word):\n        \"\"\"\n        :type word: str\n        :rtype: None\n        \"\"\"\n        for f in self.hashs:\n            index = f.hash(word)\n            self.bits[index] = 1\n\n    def contains(self, word):\n        \"\"\"\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        for f in self.hashs:\n            index = f.hash(word)\n            if self.bits[index] == 0:\n                return False\n        return True\n"
  },
  {
    "path": "lintcode/559_trie_service.py",
    "content": "\"\"\"\nDefinition of TrieNode:\nclass TrieNode:\n    def __init__(self):\n        # <key, value>: <Character, TrieNode>\n        self.children = collections.OrderedDict()\n        self.top10 = []\n\"\"\"\nclass TrieService:\n\n    def __init__(self):\n        self.root = TrieNode()\n\n    def get_root(self):\n        # Return root of trie root, and\n        # lintcode will print the tree struct.\n        return self.root\n\n    # @param {str} word a string\n    # @param {int} frequency an integer\n    # @return nothing\n    def insert(self, word, frequency):\n        if not word or len(word) < 1 \\\n                or not frequency:\n            return\n        parent = self.root\n        for char in word:\n            if char not in parent.children:\n                parent.children[char] = TrieNode()\n            parent = parent.children[char]\n\n            # To handle top10\n            parent.top10.append(frequency)\n            parent.top10.sort(reverse=True)\n            if len(parent.top10) > 10:\n                parent.top10.pop()\n"
  },
  {
    "path": "lintcode/560_friendship_service.py",
    "content": "class FriendshipService:\n    def __init__(self):\n        self.followers = {}\n        self.followings = {}\n\n    def getFollowers(self, user_id):\n        return self.get_followers(user_id)\n\n    def getFollowings(self, user_id):\n        return self.get_followings(user_id)\n\n    \"\"\"\n    @param: user_id: An integer\n    @return: all followers and sort by user_id\n    \"\"\"\n    def get_followers(self, user_id):\n        if user_id in self.followers:\n            return sorted(self.followers[user_id])\n\n        return []\n\n    \"\"\"\n    @param: user_id: An integer\n    @return: all followings and sort by user_id\n    \"\"\"\n    def get_followings(self, user_id):\n        if user_id in self.followings:\n            return sorted(self.followings[user_id])\n\n        return []\n\n    \"\"\"\n    @param: to_id: An integer\n    @param: from_id: An integer\n    @return: nothing\n    \"\"\"\n    def follow(self, to_id, from_id):\n        if from_id not in self.followings:\n            self.followings[from_id] = set()\n        self.followings[from_id].add(to_id)\n\n        if to_id not in self.followers:\n            self.followers[to_id] = set()\n        self.followers[to_id].add(from_id)\n\n    \"\"\"\n    @param: to_id: An integer\n    @param: from_id: An integer\n    @return: nothing\n    \"\"\"\n    def unfollow(self, to_id, from_id):\n        if from_id in self.followings:\n            self.followings[from_id].discard(to_id)\n\n        if to_id in self.followers:\n            self.followers[to_id].discard(from_id)\n"
  },
  {
    "path": "lintcode/563_backpack_v.py",
    "content": "\"\"\"\nDP: MLE\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an integer array and all positive numbers\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def backPackV(self, A, target):\n        if not A:\n            return 0\n\n        n = len(A)\n        dp = [[0] * (target + 1) for _ in range(n + 1)]\n        dp[0][0] = 1\n\n        for i in range(1, n + 1):\n            for j in range(target + 1):\n                dp[i][j] = dp[i - 1][j]\n                if j >= A[i - 1]:\n                    dp[i][j] += dp[i - 1][j - A[i - 1]]\n\n        return dp[n][target]\n\n\n\"\"\"\nDP: optimized space complexity\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an integer array and all positive numbers\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def backPackV(self, A, target):\n        if not A:\n            return 0\n\n        n = len(A)\n        dp = [0] * (target + 1)\n        dp[0] = 1\n\n        for i in range(n):\n            for j in range(target, A[i] - 1, -1):\n                dp[j] += dp[j - A[i]]\n\n        return dp[target]\n"
  },
  {
    "path": "lintcode/564_backpack_vi.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an integer array and all positive numbers, no duplicates\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def backPackVI(self, A, target):\n        if not A:\n            return 0\n\n        n = len(A)\n        dp = [0] * (target + 1)\n        dp[0] = 1\n\n        for i in range(1, target + 1):\n            for j in range(n):\n                if i >= A[j]:\n                    dp[i] += dp[i - A[j]]\n\n        return dp[target]\n"
  },
  {
    "path": "lintcode/565_heart_beat.py",
    "content": "class HeartBeat:\n\n    def __init__(self):\n        self.slaves_ip_list = {}\n\n    \"\"\"\n    @param: slaves_ip_list: a list of slaves'ip addresses\n    @param: k: An integer\n    @return: nothing\n    \"\"\"\n    def initialize(self, slaves_ip_list, k):\n        self.slaves_ip_list.update(dict.fromkeys(slaves_ip_list, 0))\n        self.ttl = 2 * k\n\n    \"\"\"\n    @param: timestamp: current timestamp in seconds\n    @param: slave_ip: the ip address of the slave server\n    @return: nothing\n    \"\"\"\n    def ping(self, timestamp, slave_ip):\n        if slave_ip in self.slaves_ip_list:\n            self.slaves_ip_list[slave_ip] = timestamp\n\n    \"\"\"\n    @param: timestamp: current timestamp in seconds\n    @return: a list of slaves'ip addresses that died\n    \"\"\"\n    def getDiedSlaves(self, timestamp):\n        if not timestamp:\n            return []\n        return [ ip\n            for ip, t0 in self.slaves_ip_list.items()\n            if timestamp - t0 >= self.ttl\n        ]\n"
  },
  {
    "path": "lintcode/566_gfs_client.py",
    "content": "'''\nDefinition of BaseGFSClient\nclass BaseGFSClient:\n    def readChunk(self, filename, chunkIndex):\n        # Read a chunk from GFS\n    def writeChunk(self, filename, chunkIndex, content):\n        # Write a chunk to GFS\n'''\n\n\nclass GFSClient(BaseGFSClient):\n    \"\"\"\n    @param: chunkSize: An integer\n    \"\"\"\n    def __init__(self, chunkSize):\n        BaseGFSClient.__init__(self)\n        self.chunk_size = chunkSize\n        self.chunk_num = {}\n\n    \"\"\"\n    @param: filename: a file name\n    @return: conetent of the file given from GFS\n    \"\"\"\n    def read(self, filename):\n        if filename not in self.chunk_num:\n            return\n        i, content = 0, ''\n        while i < self.chunk_num[filename]:\n            content += self.readChunk(filename, i)\n            i += 1\n        return content\n\n    \"\"\"\n    @param: filename: a file name\n    @param: content: a string\n    @return: nothing\n    \"\"\"\n    def write(self, filename, content):\n        i, j, n = 0, 0, len(content)\n        while j < n:\n            self.writeChunk(filename, i, content[j : j + self.chunk_size])\n            i += 1\n            j += self.chunk_size\n        self.chunk_num[filename] = i\n"
  },
  {
    "path": "lintcode/56_two_sum.py",
    "content": "\"\"\"\ntime: O(n)\nspace: O(n)\n\nit works even if it's not sorted\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An array of Integer\n    @param: target: target = A[index1] + A[index2]\n    @return: [index1, index2] (index1 < index2)\n    \"\"\"\n    def twoSum(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A or len(A) < 2:\n            return NOT_FOUND\n\n        remaining = {}\n        for i in range(len(A)):\n            if A[i] in remaining:\n                return [\n                    remaining[A[i]],\n                    i,\n                ]\n\n            remaining[target - A[i]] = i\n\n        return NOT_FOUND\n\n\n\"\"\"\ntime: O(nlogn)\nspace: O(n)\n\nneeds to sort in advance\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An array of Integer\n    @param: target: target = A[index1] + A[index2]\n    @return: [index1, index2] (index1 < index2)\n    \"\"\"\n    def twoSum(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A or len(A) < 2:\n            return NOT_FOUND\n\n        n = len(A)\n        A = [(A[i], i) for i in range(n)]\n        A.sort()\n\n        left, right = 0, n - 1\n        while left < right:\n            _sum = A[left][0] + A[right][0]\n            if _sum == target:\n                return sorted([\n                    A[left][1],\n                    A[right][1],\n                ])\n\n            if _sum < target:\n                left += 1\n            else:\n                right -= 1\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/573_build_post_office_ii.py",
    "content": "\"\"\"\nNote:\n- You cannot pass through wall and house, but can pass through empty.\n- You only build post office on an empty.\n\"\"\"\n\n\nimport collections\n\n\nclass Solution:\n    \"\"\"\n    BFS\n\n    1. for each house, use `BFS` in level traversal\n       to count the distance if the cell is empty and reachable\n    2. find the minimum of the total distance in each empty cell,\n       and it must be reachable for each house\n    \"\"\"\n\n    EMPTY = 0\n    HOUSE = 1\n    WALL = 2\n\n    def shortestDistance(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or not grid[0]:\n            return -1\n\n        m, n = len(grid), len(grid[0])\n        cnt = 0\n        times = collections.defaultdict(int)\n        steps = collections.defaultdict(int)\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.HOUSE:\n                    cnt += 1\n                    self.bfs(grid, x, y, times, steps)\n\n        ans = INF = float('inf')\n\n        for (x, y), t in times.items():\n            if t == cnt and steps[x, y] < ans:\n                ans = steps[x, y]\n\n        return ans if ans < INF else -1\n\n    def bfs(self, grid, x, y, times, steps):\n        m, n = len(grid), len(grid[0])\n        queue, _queue = [(x, y)], []\n        visited = set(queue)\n        step = 0\n\n        while queue:\n            step += 1\n\n            for x, y in queue:\n                for dx, dy in (\n                    (-1, 0), (1, 0),\n                    (0, -1), (0, 1),\n                ):\n                    _x = x + dx\n                    _y = y + dy\n\n                    if not (0 <= _x < m and 0 <= _y < n):\n                        continue\n                    if grid[_x][_y] != self.EMPTY:\n                        continue\n                    if (_x, _y) in visited:\n                        continue\n\n                    visited.add((_x, _y))\n                    _queue.append((_x, _y))\n\n                    steps[_x, _y] += step\n                    times[_x, _y] += 1\n\n            queue, _queue = _queue, []\n\n\nimport collections\n\n\nclass Solution:\n    \"\"\"\n    DFS: TLE\n\n    If use DFS, need to consider update min dist\n    so may visit a node many times\n    \"\"\"\n\n    EMPTY = 0\n    HOUSE = 1\n    WALL = 2\n\n    def shortestDistance(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or not grid[0]:\n            return -1\n\n        m, n = len(grid), len(grid[0])\n        cnt = 0\n        ids = collections.defaultdict(set)  # record house ids\n        steps = collections.defaultdict(int)  # total steps for all houses\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] != self.HOUSE:\n                    continue\n\n                cnt += 1\n                step = collections.defaultdict(int)  # steps for current house\n                self.dfs(grid, x, y, cnt, ids, steps, step)\n\n        ans = INF = float('inf')\n\n        for (x, y), hids in ids.items():\n            if len(hids) == cnt and steps[x, y] < ans:\n                ans = steps[x, y]\n\n        return ans if ans < INF else -1\n\n    def dfs(self, grid, x, y, id, ids, steps, step):\n        m, n = len(grid), len(grid[0])\n\n        for dx, dy in (\n            (-1, 0), (1, 0),\n            (0, -1), (0, 1),\n        ):\n            _x = x + dx\n            _y = y + dy\n\n            if not (0 <= _x < m and 0 <= _y < n):\n                continue\n            if grid[_x][_y] != self.EMPTY:\n                continue\n            if step[x, y] + 1 >= step[_x, _y] > 0:  # > 0 means visited, since its defaultdict\n                continue\n\n            ids[_x, _y].add(id)\n\n            steps[_x, _y] -= step[_x, _y]\n            step[_x, _y] = step[x, y] + 1\n            steps[_x, _y] += step[_x, _y]\n\n            self.dfs(grid, _x, _y, id, ids, steps, step)\n"
  },
  {
    "path": "lintcode/574_build_post_office.py",
    "content": "\"\"\"\nNote:\n- You can pass through house and empty.\n- You only build post office on an empty.\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Prefix Sum + Binary Searching\n    http://yuanyuanzhangcs.blogspot.hk/2017/02/build-post-office.html\n\n    for `X = [1, 2, 3, 4], x = 3`\n    and we want to get the sum of distances between `X[i]` and `x`\n    => d = (3 - 1) + (3 - 2) + (3 - 3) + (4 - 3)\n\n    so we can use binary search to find the `i` of `x` in `X`\n    => n = 4, i = 2 (since 2 < x == 3)\n    => d = x * i - (1 + 2)  +  (3 + 4) - (n - i) * x\n\n    and we building prefix sum of `X`\n    => `S = [0, 1, 3, 6, 10]`\n    => d = x * i - S[i]  +  (S[n] - S[i]) - x * (n - i)\n    \"\"\"\n\n    EMPTY = 0\n    HOUSE = 1\n\n    def shortestDistance(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or not grid[0]:\n            return -1\n\n        m, n = len(grid), len(grid[0])\n        xs, ys = [], []\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] != self.HOUSE:\n                    continue\n                xs.append(x)\n                ys.append(y)\n\n        if not xs or len(xs) == m * n:\n            return -1\n\n        ys.sort()\n\n        k = len(xs) + 1\n        psx, psy = [0] * k, [0] * k  # prefix sum\n\n        for i in range(1, k):\n            psx[i] = psx[i - 1] + xs[i - 1]\n            psy[i] = psy[i - 1] + ys[i - 1]\n\n        ans = INF = float('inf')\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] != self.EMPTY:\n                    continue\n\n                step = self.get_step(psx, xs, x) + self.get_step(psy, ys, y)\n\n                if step < ans:\n                    ans = step\n\n        return ans if ans < INF else -1\n\n    def get_step(self, ps, axis, pos):\n        n = len(axis)\n\n        if axis[0] > pos:\n            return ps[n] - pos * n\n        if axis[-1] < pos:\n            return pos * n - ps[n]\n\n        left, right = 0, n - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n\n            if axis[mid] < pos:\n                left = mid\n            else:\n                right = mid\n\n        return sum((\n            pos * right - ps[right],\n            ps[n] - ps[right] - pos * (n - right),\n        ))\n\n\nclass Solution:\n    \"\"\"\n    BFS: TLE\n\n    time: O(mn)\n    find the center of the shape composed of houses\n    and then do bfs\n    \"\"\"\n\n    EMPTY = 0\n    HOUSE = 1\n\n    def shortestDistance(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or not grid[0]:\n            return -1\n\n        m, n = len(grid), len(grid[0])\n        houses = []\n        xc = yc = 0  # the center of the shape composed of houses\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.HOUSE:\n                    houses.append((x, y))\n                    xc += x\n                    yc += y\n\n        xc //= len(houses)\n        yc //= len(houses)\n\n        ans = INF = float('inf')\n        queue = [(xc, yc)]\n        visited = set(queue)\n\n        for x, y in queue:\n            if grid[x][y] == self.EMPTY:\n                ans = min(ans, self.get_step(houses, x, y))\n\n            for dx, dy in (\n                (-1, 0), (1, 0),\n                (0, -1), (0, 1),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if (_x, _y) in visited:\n                    continue\n\n                visited.add((_x, _y))\n                queue.append((_x, _y))\n\n        return ans if ans < INF else -1\n\n    def get_step(self, houses, x, y):\n        step = 0\n\n        for _x, _y in houses:\n            step += abs(_x - x) + abs(_y - y)\n\n        return step\n\n\nclass Solution:\n    \"\"\"\n    BFS: TLE\n\n    time: O((mn)^2)\n    brute force to bfs\n    \"\"\"\n\n    EMPTY = 0\n    HOUSE = 1\n\n    def shortestDistance(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or not grid[0]:\n            return -1\n\n        m, n = len(grid), len(grid[0])\n        steps = [[0] * n for _ in range(m)]\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.HOUSE:\n                    self.bfs(grid, x, y, steps)\n\n        ans = INF = float('inf')\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] != self.EMPTY:\n                    continue\n                if steps[x][y] < ans:\n                    ans = steps[x][y]\n\n        return ans if ans < INF else -1\n\n    def bfs(self, grid, x, y, steps):\n        m, n = len(grid), len(grid[0])\n        queue, _queue = [(x, y)], []\n        visited = set(queue)\n        step = 0\n\n        while queue:\n            step += 1\n\n            for x, y in queue:\n                for dx, dy in (\n                    (-1, 0), (1, 0),\n                    (0, -1), (0, 1),\n                ):\n                    _x = x + dx\n                    _y = y + dy\n\n                    if not (0 <= _x < m and 0 <= _y < n):\n                        continue\n                    if (_x, _y) in visited:\n                        continue\n\n                    visited.add((_x, _y))\n                    steps[_x][_y] += step\n                    _queue.append((_x, _y))\n\n            queue, _queue = _queue, []\n"
  },
  {
    "path": "lintcode/575_expression_expand.py",
    "content": "class Solution:\n    def expressionExpand(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        if not s:\n            return ''\n\n        times = 0\n        stack = []\n\n        for c in s:\n            if c.isdigit():\n                times = times * 10 + int(c)\n            elif c == '[':\n                stack.append(times)\n                times = 0\n            elif c == ']':\n                part = []\n                while stack and isinstance(stack[-1], str):\n                    part.append(stack.pop())\n                cnt = int(stack.pop()) if stack else 1\n                stack.append(cnt * ''.join(reversed(part)))\n            else:\n                stack.append(c)\n\n        return ''.join(stack)\n"
  },
  {
    "path": "lintcode/578_lowest_common_ancestor_iii.py",
    "content": "\"\"\"\nNotice:\nnode A or node B may not exist in tree.\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def lowestCommonAncestor3(self, root, a, b):\n        \"\"\"\n        :type root: TreeNode\n        :type a: TreeNode\n        :type b: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root:\n            return\n\n        lca, has_a, has_b = self.divide_conquer(root, a, b)\n\n        return lca if has_a and has_b else None\n\n    def divide_conquer(self, node, a, b):\n        if not node:\n            return None, False, False\n\n        left, a_in_left, b_in_left = self.divide_conquer(node.left, a, b)\n        right, a_in_right, b_in_right = self.divide_conquer(node.right, a, b)\n\n        has_a = a_in_left or a_in_right or node is a\n        has_b = b_in_left or b_in_right or node is b\n\n        if node is a or node is b:\n            return node, has_a, has_b\n        if left and right:\n            return node, has_a, has_b\n        if left:\n            return left, has_a, has_b\n        if right:\n            return right, has_a, has_b\n\n        return None, has_a, has_b\n"
  },
  {
    "path": "lintcode/57_3sum.py",
    "content": "class Solution:\n    def threeSum(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not nums or len(nums) < 3:\n            return ans\n\n        n = len(nums)\n        nums.sort()\n\n        for a in range(n - 2):\n            if a > 0 and nums[a] == nums[a - 1]:\n                continue\n\n            b, c = a + 1, n - 1\n\n            while b < c:\n                total = nums[a] + nums[b] + nums[c]\n\n                if total == 0:\n                    ans.append([nums[a], nums[b], nums[c]])\n                    b += 1\n                    c -= 1\n                    while b < c and nums[b] == nums[b - 1]:\n                        b += 1\n                    while b < c and nums[c] == nums[c + 1]:\n                        c -= 1\n                elif total < 0:\n                    b += 1\n                else:\n                    c -= 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/582_word_break_ii.py",
    "content": "class Solution:\n    \"\"\"\n    dfs/dp: optimized by memory searching\n    \"\"\"\n    def wordBreak(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: list[str]\n        :rtype: list[str]\n        \"\"\"\n        return self.dfs(s, set(words), {})\n\n    def dfs(self, s, words, memo):\n        if s in memo:\n            return memo[s]\n\n        res = []\n\n        if not s:\n            return res\n\n        n = len(s)\n        for size in range(1, n + 1):\n            prefix = s[:size]\n\n            if prefix not in words:\n                continue\n\n            if size == n:\n                res.append(prefix)\n                continue\n\n            for word in self.dfs(s[size:], words, memo):\n                res.append('{0} {1}'.format(prefix, word))\n\n        memo[s] = res\n        return res\n\n\nclass Solution:\n    \"\"\"\n    dfs: TLE\n\n    bad in edge case:\n    \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n    [\"a\",\"aa\",\"aaa\",\"aaaa\",\"aaaaa\",\"aaaaaa\",\"aaaaaaa\",\"aaaaaaaa\",\"aaaaaaaaa\",\"aaaaaaaaaa\"]\n    \"\"\"\n    def wordBreak(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: list[str]\n        :rtype: list[str]\n        \"\"\"\n        ans = []\n\n        if not words:\n            return ans\n\n        self.dfs(s, words, ans, [])\n\n        return ans\n\n    def dfs(self, s, words, ans, path):\n        if not s:\n            ans.append(' '.join(path))\n            return\n\n        for word in words:\n            if not word or s.find(word) != 0:\n                # 1. no word\n                # 2. current word must be the first in s passed in prev\n                continue\n\n            path.append(word)\n            self.dfs(s[len(word):], words, ans, path)\n            path.pop()\n"
  },
  {
    "path": "lintcode/584_drop_eggs_ii.py",
    "content": "\"\"\"\nREF: http://massivealgorithms.blogspot.jp/2014/07/dynamic-programming-set-11-egg-dropping.html\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: m: the number of eggs\n    @param: n: the number of floors\n    @return: the number of drops in the worst case\n    \"\"\"\n    def dropEggs2(self, m, n):\n        if not m or not n:\n            return 0\n\n        INFINITY = float('inf')\n\n        \"\"\"\n        `dp[i][j]` means the minimum drops to verify\n        the worst case in `j` floors with `i` eggs\n        \"\"\"\n        dp = [[0] * (n + 1) for _ in range(m + 1)]\n\n        \"\"\"\n        only one egg\n        \"\"\"\n        for i in range(1, m + 1):\n            dp[i][1] = 1\n\n        \"\"\"\n        only one floor\n        \"\"\"\n        for j in range(1, n + 1):\n            dp[1][j] = j\n\n        for i in range(2, m + 1):\n            for j in range(2, n + 1):\n                dp[i][j] = INFINITY\n\n                for k in range(1, j + 1):\n                    \"\"\"\n                    backtracking to drop one egg on arbitrary floor `k`\n                    there is two cases, if previous egg is:\n\n                    1. broken: reduce to subproblem (m - 1, k - 1)\n                        dp[i - 1][k - 1] + 1 drop\n                    2. not broken: reduce to subproblem (m, n - k)\n                        dp[i][j - k] + 1 drop\n                    \"\"\"\n                    _worst = max(dp[i - 1][k - 1], dp[i][j - k]) + 1\n\n                    \"\"\"\n                    find the minimum worst case\n                    \"\"\"\n                    if _worst < dp[i][j]:\n                        dp[i][j] = _worst\n\n        return dp[m][n]\n"
  },
  {
    "path": "lintcode/585_maximum_number_in_mountain_sequence.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: a mountain sequence which increase firstly and then decrease\n    @return: then mountain top\n    \"\"\"\n    def mountainSequence(self, nums):\n        if not nums:\n            return -1\n\n        l, m, r = 0, 0, len(nums) - 1\n\n        while l + 1 < r:\n            m = l + (r - l) // 2\n            \"\"\"\n            `m+1` will not out of range\n            if len(nums) == 1 || 2, the code in this loop will not execute\n            \"\"\"\n            if nums[m] > nums[m+1]:\n                r = m\n            else:\n                l = m\n\n        return max(nums[l], nums[r])\n"
  },
  {
    "path": "lintcode/586_sqrtx_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param: x: a double\n    @return: the square root of x\n    \"\"\"\n    def sqrt(self, x):\n        if not x:\n            return x\n\n        left = 0\n        right = x if x > 1 else 1\n        eps = 1e-10  # the precision needs `1e-8`, check more two digits\n        while right - left > eps:\n            mid = (left + right) / 2.0\n            if mid * mid < x:\n                left = mid\n            else:\n                right = mid\n\n        return left\n"
  },
  {
    "path": "lintcode/587_two_sum_unique_pairs.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: an array of integer\n    @param: target: An integer\n    @return: An integer\n    \"\"\"\n    def twoSum6(self, nums, target):\n        ans = 0\n        if not nums:\n            return ans\n\n        nums.sort()\n\n        left, right = 0, len(nums) - 1\n        _sum = 0\n        while left < right:\n            _sum = nums[left] + nums[right]\n            if _sum == target:\n                ans += 1\n                left += 1\n                right -= 1\n                while left < right and nums[right] == nums[right + 1]:\n                    right -= 1\n                while left < right and nums[left] == nums[left - 1]:\n                    left -= 1\n                continue\n\n            if _sum > target:\n                right -= 1\n            else:\n                left += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/589_connecting_graph.py",
    "content": "class ConnectingGraph:\n    \"\"\"\n    @param: n: An integer\n    \"\"\"\n    def __init__(self, n):\n        if not n:\n            return\n\n        self.N = {}\n        for i in range(1, n + 1):\n            self.N[i] = i\n\n    def find(self, a):\n        if self.N[a] == a:\n            return a\n\n        self.N[a] = self.find(self.N[a])\n        return self.N[a]\n\n    \"\"\"\n    @param: a: An integer\n    @param: b: An integer\n    @return: nothing\n    \"\"\"\n    def connect(self, a, b):\n        _a = self.find(a)\n        _b = self.find(b)\n        if _a != _b:\n            self.N[_a] = _b\n\n    \"\"\"\n    @param: a: An integer\n    @param: b: An integer\n    @return: A boolean\n    \"\"\"\n    def query(self, a, b):\n        _a = self.find(a)\n        _b = self.find(b)\n        return _a == _b\n"
  },
  {
    "path": "lintcode/58_4sum.py",
    "content": "class Solution:\n    def fourSum(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not nums or len(nums) < 4 or target is None:\n            return ans\n\n        n = len(nums)\n        nums.sort()\n\n        for a in range(n - 3):\n            if a > 0 and nums[a] == nums[a - 1]:\n                continue\n\n            for b in range(a + 1, n - 2):\n                if b > a + 1 and nums[b] == nums[b - 1]:\n                    continue\n\n                c, d = b + 1, n - 1\n\n                while c < d:\n                    total = nums[a] + nums[b] + nums[c] + nums[d]\n\n                    if total == target:\n                        ans.append([nums[a], nums[b], nums[c], nums[d]])\n                        c += 1\n                        d -= 1\n                        while c < d and nums[c] == nums[c - 1]:\n                            c += 1\n                        while c < d and nums[d] == nums[d + 1]:\n                            d -= 1\n                    elif total < target:\n                        c += 1\n                    else:\n                        d -= 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/590_connecting_graph_ii.py",
    "content": "class ConnectingGraph2:\n    \"\"\"\n    @param: n: An integer\n    \"\"\"\n    def __init__(self, n):\n        if n < 1:\n            return\n        self.nodes = {}\n        self.count = {}\n        for i in range(n):\n            self.nodes[i + 1] = i + 1\n            self.count[i + 1] = 1\n\n    def find(self, a):\n        if self.nodes[a] == a:\n            return a\n        self.nodes[a] = self.find(self.nodes[a])\n        return self.nodes[a]\n\n    \"\"\"\n    @param: a: An integer\n    @param: b: An integer\n    @return: nothing\n    \"\"\"\n    def connect(self, a, b):\n        root_a = self.find(a)\n        root_b = self.find(b)\n        if root_a != root_b:\n            # Assign a as b's child set\n            self.nodes[root_a] = root_b\n            self.count[root_b] += self.count[root_a]\n\n    \"\"\"\n    @param: a: An integer\n    @return: An integer\n    \"\"\"\n    def query(self, a):\n        root_a = self.find(a)\n        return self.count[root_a]\n"
  },
  {
    "path": "lintcode/591_connecting_graph_iii.py",
    "content": "class ConnectingGraph3:\n    \"\"\"\n    @param: n: An integer\n    \"\"\"\n    def __init__(self, n):\n        if n < 1:\n            return\n        self.nodes = {}\n        self.count = n\n        for i in range(n):\n            self.nodes[i + 1] = i + 1\n\n    def find(self, a):\n        if self.nodes[a] == a:\n            return a\n        self.nodes[a] = self.find(self.nodes[a])\n        return self.nodes[a]\n\n    \"\"\"\n    @param: a: An integer\n    @param: b: An integer\n    @return: nothing\n    \"\"\"\n    def connect(self, a, b):\n        root_a = self.find(a)\n        root_b = self.find(b)\n        if root_a != root_b:\n            self.nodes[root_a] = root_b\n            self.count -= 1\n\n    \"\"\"\n    @return: An integer\n    \"\"\"\n    def query(self):\n        return self.count\n"
  },
  {
    "path": "lintcode/594_strstr_ii.py",
    "content": "\"\"\"\nRabin-Karp algorithm\n\nhttps://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm\n\n\nMain Concept:\n\ngiven S == 'abcde' and T == 'bcd'\n\n1. convert T into hashcode `tcode`\n2. iterate S every `n` chars, and compare with `tcode`,\n   continue to add `S[i]` and kick out `S[i - n]`,\n\n    a b c d e\n    a b c\n      b c d\n        c d e\n\n3. so we need to reduce `ord(S[i - n]) * MG ** (n - 1)` every turns\n   => calculate `MG ** (n - 1)` in advance to save time\n4. if became negative, add `MOD` to back to positive\n\nTest Case:\n\n\"abcde\"\n\"e\"\n\n\"abcdef\"\n\"bcd\"\n\"\"\"\n\n\nclass Solution:\n    def strStr2(self, S, T):\n        \"\"\"\n        :type S: List[str]\n        :type T: List[str]\n        :rtype: int\n        \"\"\"\n\n        NOT_FOUND = -1\n\n        if S is not None and T is '':\n            return 0\n\n        if not S or not T:\n            return NOT_FOUND\n\n        m, n = len(S), len(T)\n        if n > m:\n            return NOT_FOUND\n\n        MOD = 1000000  # hashsize to mod\n        MG = 31  # magic number\n        A = ord('a')\n\n        p = 1  # `p == MG ** (n - 1)`\n        tcode = 0  # the code of T\n        for i in range(n):\n            tcode = (tcode * MG + ord(T[i]) - A) % MOD\n\n            if i == 0:\n                continue\n            \"\"\"\n            continue here since p only need `n - 1` times\n            \"\"\"\n            p = (p * MG) % MOD\n\n        _code = 0\n        for i in range(m):\n            \"\"\"\n            kick out `S[i - n]`\n            \"\"\"\n            if i >= n:\n                _code = (_code - (ord(S[i - n]) - A) * p) % MOD\n\n            if _code < 0:\n                _code += MOD\n\n            \"\"\"\n            Add `S[i]`\n            \"\"\"\n            _code = (_code * MG + ord(S[i]) - A) % MOD\n\n            if _code == tcode and S[i - n + 1:i + 1] == T:\n                return i - n + 1\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/595_binary_tree_longest_consecutive_sequence.py",
    "content": "\"\"\"\nThe longest consecutive path need to be from parent to child (cannot be the reverse).\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Bottom Up\n    \"\"\"\n    def longestConsecutive(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        return self.divide_conquer(root)[0]\n\n    def divide_conquer(self, node):\n        if not node:\n            return 0, 0\n\n        size = 1\n        down = 0\n\n        for branch in ('left', 'right'):\n            child = getattr(node, branch)\n\n            if not child:\n                continue\n\n            _size, _down = self.divide_conquer(child)\n\n            if child.val - 1 == node.val and _down + 1 > down:\n                down = _down + 1\n\n            if _size > size:\n                size = _size\n\n        if down + 1 > size:\n            size = down + 1\n\n        return size, down\n\n\nclass Solution:\n    \"\"\"\n    Top Down\n    \"\"\"\n    def longestConsecutive(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        return self.divide_conquer(root, 0, 0)\n\n    def divide_conquer(self, node, parent_val, _size):\n        if not node:\n            return 0\n\n        size = 1\n\n        if parent_val + 1 == node.val:\n            size += _size\n\n        left = self.divide_conquer(node.left, node.val, size)\n        right = self.divide_conquer(node.right, node.val, size)\n\n        return max(size, left, right)\n"
  },
  {
    "path": "lintcode/596_minimum_subtree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\"\"\"\n\n\nclass Solution:\n    min_sum = float('inf')\n    node = None\n\n    \"\"\"\n    @param: root: the root of binary tree\n    @return: the root of the minimum subtree\n    \"\"\"\n    def findSubtree(self, root):\n        self._traversal(root)\n        return self.node\n\n    def _traversal(self, node):\n        if not node:\n            return 0\n\n        left_sum = self._traversal(node.left)\n        right_sum = self._traversal(node.right)\n        subtree_sum = left_sum + right_sum + node.val\n\n        if subtree_sum < self.min_sum:\n            self.min_sum = subtree_sum\n            self.node = node\n\n        return subtree_sum\n"
  },
  {
    "path": "lintcode/597_subtree_with_maximum_average.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        this.val = val\n        this.left, this.right = None, None\n\"\"\"\n\n\"\"\"\nTest Case:\n\n{1,-5,11,1,2,4,-2}\n: subtree_avg = subtree_sum / subtree_size -> subtree_avg = subtree_sum * 1.0 / subtree_size\n\n{-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16}\n: max_avg = 0 -> max_avg = float('-inf')\n\"\"\"\n\nclass Solution:\n    max_avg = float('-inf')\n    max_node = None\n\n    \"\"\"\n    @param: root: the root of binary tree\n    @return: the root of the maximum average of subtree\n    \"\"\"\n    def findSubtree2(self, root):\n        self._traversal(root)\n        return self.max_node\n\n    def _traversal(self, node):\n        if not node:\n            return 0, 0\n\n        left_sum, left_size = self._traversal(node.left)\n        right_sum, right_size = self._traversal(node.right)\n\n        subtree_sum = left_sum + right_sum + node.val\n        subtree_size = left_size + right_size + 1\n        subtree_avg = subtree_sum * 1.0 / subtree_size\n\n        if subtree_avg > self.max_avg:\n            self.max_avg = subtree_avg\n            self.max_node = node\n\n        return subtree_sum, subtree_size\n"
  },
  {
    "path": "lintcode/598_zombie_in_matrix.py",
    "content": "class Solution:\n    PEOPLE = 0\n    ZOMBIE = 1\n    WALL = 2\n\n    \"\"\"\n    @param: grid: a 2D integer grid\n    @return: an integer\n    \"\"\"\n    def zombie(self, grid):\n        if not grid:\n            return -1\n\n        vector = (\n            ( 0, -1),\n            ( 0,  1),\n            (-1,  0),\n            ( 1,  0),\n        )\n        m, n = len(grid), len(grid[0])\n\n        queue, _queue = [], None\n        days = -1\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.ZOMBIE:\n                    queue.append((x, y))\n\n        while queue:\n            days += 1\n            _queue = []\n            for x, y in queue:\n                for dx, dy in vector:\n                    _x = x + dx\n                    _y = y + dy\n                    if 0 <= _x < m and 0 <= _y < n \\\n                            and grid[_x][_y] == self.PEOPLE:\n                        grid[_x][_y] = self.ZOMBIE\n                        _queue.append((_x, _y))\n            queue = _queue\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.PEOPLE:\n                    return -1\n\n        return days\n"
  },
  {
    "path": "lintcode/599_insert_into_a_cyclic_sorted_list.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: node: a list node in the list\n    @param: x: An integer\n    @return: the inserted new list node\n    \"\"\"\n    def insert(self, node, x):\n        if not node:\n            node = ListNode(x)\n            node.next = node\n            return node\n\n        pre, cur = None, node\n        while True:\n            pre = cur\n            cur = cur.next\n\n            # in the list\n            if pre.val <= x <= cur.val:\n                break\n\n            # at the boundary between minimum and maximum\n            if (pre.val > cur.val) and (x < cur.val or x > pre.val):\n                break\n\n            # if `cur` have already traversed the list once\n            if cur is node:\n                break\n\n        new_node = ListNode(x)\n        new_node.next = cur\n        pre.next = new_node\n        return new_node\n"
  },
  {
    "path": "lintcode/59_3sum_closest.py",
    "content": "class Solution:\n    def threeSumClosest(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        if not nums or len(nums) < 3 or target is None:\n            return -1\n\n        ans = INF = float('inf')\n        n = len(nums)\n        nums.sort()\n\n        for a in range(n - 2):\n            if a > 0 and nums[a] == nums[a - 1]:\n                continue\n\n            b, c = a + 1, n - 1\n\n            while b < c:\n                total = nums[a] + nums[b] + nums[c]\n\n                if total == target:\n                    return total\n\n                if abs(total - target) < abs(ans - target):\n                    ans = total\n\n                if total < target:\n                    b += 1\n                else:\n                    c -= 1\n\n        return ans if ans < INF else -1\n"
  },
  {
    "path": "lintcode/5_kth_largest_element.py",
    "content": "class Solution:\n\n    def kthLargestElement(self, k, nums):\n        nums.sort()\n        return nums[-k]\n"
  },
  {
    "path": "lintcode/600_smallest_rectangle_enclosing_black_pixels.py",
    "content": "class Solution:\n    def minArea(self, image, x, y):\n        \"\"\"\n        :type image: list[str]\n        :type x: int\n        :type y: int\n        :rtype: int\n        \"\"\"\n        if not image or not image[0]:\n            return 0\n\n        m, n = len(image), len(image[0])\n\n        top = self.binary_search(image, 0, x, self.is_empty_row)\n        bottom = self.binary_search(image, m - 1, x, self.is_empty_row)\n        left = self.binary_search(image, 0, y, self.is_empty_col)\n        right = self.binary_search(image, n - 1, y, self.is_empty_col)\n\n        return (bottom - top + 1) * (right - left + 1)\n\n    def binary_search(self, image, start, end, is_empty):\n        check = None\n\n        if start < end:\n            check = lambda start, end: start + 1 < end\n        else:\n            check = lambda start, end: start - 1 > end\n\n        while check(start, end):\n            mid = (start + end) // 2\n\n            if is_empty(image, mid):\n                start = mid\n            else:\n                end = mid\n\n        return end if is_empty(image, start) else start\n\n    def is_empty_row(self, image, x):\n        for col in image[x]:\n            if col == '1':\n                return False\n        return True\n\n    def is_empty_col(self, image, y):\n        for row in image:\n            if row[y] == '1':\n                return False\n        return True\n"
  },
  {
    "path": "lintcode/601_flatten_2d_vector.py",
    "content": "\"\"\"\nYour Vector2D object will be instantiated and called as such:\ni, v = Vector2D(vec2d), []\nwhile i.hasNext(): v.append(i.next())\n\"\"\"\n\n\nclass Vector2D:\n    # @param vec2d {List[List[int]]}\n    def __init__(self, vec2d):\n        self.g = vec2d\n        self.x = 0\n        self.y = 0\n\n    # @return {int} a next element\n    def next(self):\n        if not self.hasNext():\n            return -1\n\n        x = self.x\n        y = self.y\n\n        self.y += 1\n\n        return self.g[x][y]\n\n    # @return {boolean} true if it has next element\n    # or false\n    def hasNext(self):\n        while self.x < len(self.g):\n            if self.y < len(self.g[self.x]):\n                return True\n\n            self.x += 1\n            self.y = 0\n\n        return False\n"
  },
  {
    "path": "lintcode/602_russian_doll_envelopes.py",
    "content": "\"\"\"\nDP: time => O(nlogn)\n\nREF: https://leetcode.com/problems/russian-doll-envelopes/discuss/82763\n\"\"\"\nfrom bisect import bisect_left\n\n\nclass Solution:\n    \"\"\"\n    @param: E: a number of envelopes with widths and heights\n    @return: the maximum number of envelopes\n    \"\"\"\n    def maxEnvelopes(self, E):\n        if not E or not E[0] or len(E[0]) != 2:\n            return 0\n\n        E.sort(key=lambda e: (e[0], -e[1]))\n\n        dp = [0] * len(E)\n        size = 0\n        for _, h in E:\n            i = bisect_left(dp, h, 0, size)\n            dp[i] = h\n            if i == size:\n                size += 1\n\n        return size\n\n\n\"\"\"\nDP: TLE\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: E: a number of envelopes with widths and heights\n    @return: the maximum number of envelopes\n    \"\"\"\n    def maxEnvelopes(self, E):\n        ans = 0\n        if not E:\n            return ans\n\n        n = len(E)\n\n        \"\"\"\n        `dp[i]` means the maximum number of envelopes\n        if the `i`th envelope is outermost\n        \"\"\"\n        dp = [1] * n\n\n        E.sort()\n\n        for i in range(n):\n            for j in range(i):\n                if (E[j][0] < E[i][0] and E[j][1] < E[i][1] and\n                    dp[j] + 1 > dp[i]):\n                    dp[i] = dp[j] + 1\n                if dp[i] > ans:\n                    ans = dp[i]\n\n        return ans\n"
  },
  {
    "path": "lintcode/603_largest_divisible_subset.py",
    "content": "class Solution:\n    def largestDivisibleSubset(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n        if not A:\n            return ans\n\n        n = len(A)\n        if n == 1:\n            return A\n\n        A.sort()\n\n        \"\"\"\n        this problem similar with LIS\n\n        `dp[i]` means the maximum size of subset end at `i`\n        note that there is size, so init with `1`\n\n        `pi[i]` records the previous num in ans, and allow to backtrack\n        to find all num in ans\n\n        `pe` means path end, to record the LDS end\n        \"\"\"\n        dp = [1] * n\n        pi = [0] * n\n        pe = max_size = 0\n\n        for i in range(n):\n            for j in range(i):\n                \"\"\"\n                backtracking\n\n                `A[i]` is larger than `A[j]`,\n                so check `A[i] % A[j]` if its zero\n                \"\"\"\n                if A[i] % A[j] == 0 and dp[j] + 1 > dp[i]:\n                    dp[i] = dp[j] + 1\n                    pi[i] = j\n\n                if dp[i] > max_size:\n                    max_size = dp[i]\n                    pe = i\n\n        ans = [0] * max_size\n        for i in range(max_size - 1, -1, -1):\n            ans[i] = A[pe]\n            pe = pi[pe]\n\n        return ans\n"
  },
  {
    "path": "lintcode/604_window_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: a list of integers.\n    @param: k: length of window.\n    @return: the sum of the element inside the window at each moving.\n    \"\"\"\n    def winSum(self, A, k):\n        ans = []\n        if (not A or not k or k <= 0 or\n            len(A) < k):\n            return ans\n\n        _sum = 0\n        for i in range(len(A)):\n            _sum += A[i]\n\n            if i < k - 1:\n                continue\n\n            ans.append(_sum)\n\n            _sum -= A[i - k + 1]\n\n        return ans\n"
  },
  {
    "path": "lintcode/605_sequence_reconstruction.py",
    "content": "\"\"\"\nMain Concept:\n\nTopological Sort\n1. record `edges` and `indegrees` from `seqs`, and only allow `num` in `org`\n2. iterate `org` in order, check if there is only one path to get `org[-1]`\n\"\"\"\n\n\nclass Solution:\n    def sequenceReconstruction(self, org, seqs):\n        \"\"\"\n        :type org: list[int]\n        :type seqs: list[list[int]]\n        :rtype: bool\n        \"\"\"\n        if org is None or seqs is None:\n            return False\n\n        n = len(org)\n        edges = dict.fromkeys(org)\n        indeg = dict.fromkeys(org, 0)\n\n        cnt = 0\n        for seq in seqs:\n            if not seq:\n                continue\n\n            cnt += len(seq)\n\n            for i in range(len(seq)):\n                if not (1 <= seq[i] <= n):\n                    return False\n                if not edges[seq[i]]:\n                    edges[seq[i]] = set()\n\n                # dedup same edge\n                if i > 0 and seq[i] not in edges[seq[i - 1]]:\n                    indeg[seq[i]] += 1\n                    edges[seq[i - 1]].add(seq[i])\n\n        # for case: org == [1], seqs == [[], []]\n        if cnt < n:\n            return False\n\n        for i in range(n - 1):\n            if indeg[org[i]] != 0:\n                return False\n            if org[i + 1] not in edges[org[i]]:\n                return False\n            indeg[org[i + 1]] -= 1\n\n        return True\n"
  },
  {
    "path": "lintcode/606_kth_largest_element_ii.py",
    "content": "from heapq import heappop, heappush\n\n\nclass Solution:\n    \"\"\"\n    @param: nums: an integer unsorted array\n    @param: k: an integer from 1 to n\n    @return: the kth largest element\n    \"\"\"\n    def kthLargestElement2(self, nums, k):\n        if not nums or not k:\n            return -1\n\n        heap = []\n        for num in nums:\n            heappush(heap, num)\n\n            if len(heap) > k:\n                heappop(heap)\n\n        return heappop(heap)\n"
  },
  {
    "path": "lintcode/607_two_sum_data_structure_design.py",
    "content": "class TwoSum:\n    count = {}\n\n    \"\"\"\n    @param: number: An integer\n    @return: nothing\n    \"\"\"\n    def add(self, number):\n        if number in self.count:\n            self.count[number] += 1\n        else:\n            self.count[number] = 1\n\n    \"\"\"\n    @param: value: An integer\n    @return: Find if there exists any pair of numbers which sum is equal to the value.\n    \"\"\"\n    def find(self, value):\n        for num in self.count:\n            remaining = value - num\n            if remaining not in self.count:\n                continue\n            if remaining != num:\n                return True\n            if remaining == num and self.count[num] > 1:\n                return True\n        return False\n"
  },
  {
    "path": "lintcode/608_two_sum_input_array_is_sorted.py",
    "content": "\"\"\"\ntime: O(n)\nspace: O(n)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an array of Integer\n    @param: target: target = A[index1] + A[index2]\n    @return: [index1 + 1, index2 + 1] (index1 < index2)\n    \"\"\"\n    def twoSum(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A:\n            return NOT_FOUND\n\n        remaining = {}\n        for i in range(len(A)):\n            if A[i] in remaining:\n                return [\n                    remaining[A[i]] + 1,\n                    i + 1,\n                ]\n            remaining[target - A[i]] = i\n\n        return NOT_FOUND\n\n\n\"\"\"\ntime: O(n)\nspace: O(1)\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an array of Integer\n    @param: target: target = A[index1] + A[index2]\n    @return: [index1 + 1, index2 + 1] (index1 < index2)\n    \"\"\"\n    def twoSum(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A:\n            return NOT_FOUND\n\n        left, right = 0, len(A) - 1\n        while left < right:\n            _sum = A[left] + A[right]\n            if _sum == target:\n                return [left + 1, right + 1]\n            if _sum < target:\n                left += 1\n            else:\n                right -= 1\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/609_two_sum_less_than_or_equal_to_target.py",
    "content": "class Solution:\n    \"\"\"\n    @param: nums: an array of integer\n    @param: target: an integer\n    @return: an integer\n    \"\"\"\n    def twoSum5(self, nums, target):\n        ans = 0\n\n        if not nums or len(nums) < 2:\n            return ans\n\n        nums.sort()\n\n        left, right = 0, len(nums) - 1\n        while left < right:\n            if nums[left] + nums[right] <= target:\n                # the count of connections from `left` to `right`\n                # e.g, from 1 to 4, 1-2, 1-3, 1-4, got 3 connections\n                ans += right - left\n                left += 1\n            else:\n                right -= 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/610_two_sum_difference_equals_to_target.py",
    "content": "\"\"\"\ntime: O(n)\nspace: O(n)\n\nit works even if it's not sorted\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an array of Integer\n    @param: target: an integer\n    @return: [index1 + 1, index2 + 1] (index1 < index2)\n    \"\"\"\n    def twoSum7(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A or len(A) < 2:\n            return NOT_FOUND\n\n        remaining = {}\n        for i in range(len(A)):\n            \"\"\"\n            if a - b = t\n            => a = b + t\n            \"\"\"\n            if A[i] + target in remaining:\n                return [\n                    remaining[A[i] + target] + 1,\n                    i + 1\n                ]\n\n            \"\"\"\n            if b - a = t\n            => a = b - t\n            \"\"\"\n            if A[i] - target in remaining:\n                return [\n                    remaining[A[i] - target] + 1,\n                    i + 1\n                ]\n\n            remaining[A[i]] = i\n\n        return NOT_FOUND\n\n\n\"\"\"\ntime: O(n)\nspace: O(n)\n\nneeds to sort in advance\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an array of Integer\n    @param: target: an integer\n    @return: [index1 + 1, index2 + 1] (index1 < index2)\n    \"\"\"\n    def twoSum7(self, A, target):\n        NOT_FOUND = [-1, -1]\n        if not A or len(A) < 2:\n            return NOT_FOUND\n\n        if target < 0:\n            target = -1 * target\n\n        n = len(A)\n        A = [(A[i], i) for i in range(n)]\n        A.sort()\n\n        left = 0\n        for right in range(1, n):\n            while left + 1 < right and A[right][0] - A[left][0] > target:\n                left += 1\n            if A[right][0] - A[left][0] == target:\n                return sorted([\n                    A[left][1] + 1,\n                    A[right][1] + 1\n                ])\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/611_knight_shortest_path.py",
    "content": "\"\"\"\nDefinition for a point.\nclass Point:\n    def __init__(self, a=0, b=0):\n        self.x = a\n        self.y = b\n\"\"\"\n\n\nclass Solution:\n    V = (\n        (-2, -1),\n        ( 2,  1),\n        (-2,  1),\n        ( 2, -1),\n        (-1, -2),\n        ( 1,  2),\n        (-1,  2),\n        ( 1, -2),\n    )\n\n    \"\"\"\n    @param: G: a chessboard included 0 (false) and 1 (true)\n    @param: S: a point\n    @param: T: a point\n    @return: the shortest path\n    \"\"\"\n    def shortestPath(self, G, S, T):\n        if not G or not S or not T:\n            return -1\n\n        INFINITY = float('inf')\n        m, n = len(G), len(G[0])\n        min_steps = [[INFINITY] * n for _ in range(m)]\n\n        queue = [S]\n        _queue = None\n        _x = _y = steps = 0\n\n        while queue:\n            _queue = []\n            steps += 1\n\n            for P in queue:\n                for dx, dy in self.V:\n                    _x = P.x + dx\n                    _y = P.y + dy\n\n                    if (0 <= _x < m and 0 <= _y < n and\n                        not G[_x][_y] and\n                        steps < min_steps[_x][_y]):\n\n                        if _x == T.x and _y == T.y:\n                            return steps\n\n                        min_steps[_x][_y] = steps\n                        _queue.append(Point(_x, _y))\n\n            queue = _queue\n\n        return -1\n"
  },
  {
    "path": "lintcode/612_k_closest_points.py",
    "content": "\"\"\"\nDefinition for a point.\nclass Point:\n    def __init__(self, a=0, b=0):\n        self.x = a\n        self.y = b\n\"\"\"\nimport heapq\n\n\nclass Solution:\n    \"\"\"\n    max heap\n    \"\"\"\n    def kClosest(self, points, origin, k):\n        \"\"\"\n        :type points: list[Point]\n        :type origin: Point\n        :type k: int\n        :rtype: list[Point]\n        \"\"\"\n        ans = []\n\n        if not points or not origin or not k:\n            return ans\n\n        for i in range(len(points)):\n            distance = self.get_distance(origin, points[i])\n            heapq.heappush(ans, (-distance, i))\n\n            if len(ans) > k:\n                heapq.heappop(ans)\n\n        ans.sort(key=lambda a: (-a[0], points[a[1]].x, points[a[1]].y))\n\n        return [points[i] for _, i in ans]\n\n    def get_distance(self, p, q):\n        dx = p.x - q.x\n        dy = p.y - q.y\n        return dx * dx + dy * dy\n\n\nimport heapq\n\n\nclass Solution:\n    \"\"\"\n    min heap\n    \"\"\"\n    def kClosest(self, points, origin, k):\n        \"\"\"\n        :type points: list[Point]\n        :type origin: Point\n        :type k: int\n        :rtype: list[Point]\n        \"\"\"\n        ans = []\n\n        if not points or not origin or not k:\n            return ans\n\n        heap = []\n\n        for i in range(len(points)):\n            distance = self.get_distance(origin, points[i])\n            heapq.heappush(heap, (distance, i))\n\n        for _ in range(k):\n            distance, i = heapq.heappop(heap)\n            ans.append((distance, points[i]))\n\n        ans.sort(key=lambda a: (a[0], a[1].x, a[1].y))\n\n        return [p for _, p in ans]\n\n    def get_distance(self, p, q):\n        dx = p.x - q.x\n        dy = p.y - q.y\n        return dx * dx + dy * dy\n"
  },
  {
    "path": "lintcode/613_high_five.py",
    "content": "\"\"\"\nDefinition for a Record\nclass Record:\n    def __init__(self, id, score):\n        self.id = id\n        self.score = score\n\"\"\"\nfrom heapq import heappop, heappush\n\n\nclass Solution:\n    # @param {Record[]} results a list of <student_id, score>\n    # @return {dict(id, average)} find the average of 5 highest scores for each person\n    # <key, value> (student_id, average_score)\n    def highFive(self, results):\n        ans = {}\n        if not results:\n            return ans\n\n        k = 5\n        top_k = {}\n\n        for r in results:\n            if r.id not in top_k:\n                top_k[r.id] = []\n\n            heappush(top_k[r.id], r.score)\n\n            if len(top_k[r.id]) > k:\n                heappop(top_k[r.id])\n\n        _sum = 0\n        for id, scores in top_k.items():\n            _sum = 0\n            for score in scores:\n                _sum += score\n\n            ans[id] = _sum * 1.0 / k\n\n        return ans\n"
  },
  {
    "path": "lintcode/614_binary_tree_longest_consecutive_sequence_ii.py",
    "content": "\"\"\"\nThe path could be start and end at any node in the tree\n\n\nIf use top down in this case, still need return the result from bottom\n=> just use bottom up\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Bottom Up\n    \"\"\"\n    def longestConsecutive2(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        return self.divide_conquer(root)[0]\n\n    def divide_conquer(self, node):\n        if not node:\n            return 0, 0, 0\n\n        size = 1\n        up = down = 0\n\n        for branch in ('left', 'right'):\n            child = getattr(node, branch)\n\n            if not child:\n                continue\n\n            _size, _up, _down = self.divide_conquer(child)\n\n            if child.val + 1 == node.val and _up + 1 > up:\n                up = _up + 1\n\n            if child.val - 1 == node.val and _down + 1 > down:\n                down = _down + 1\n\n            if _size > size:\n                size = _size\n\n        if up + down + 1 > size:\n            size = up + down + 1\n\n        return size, up, down\n"
  },
  {
    "path": "lintcode/615_course_schedule.py",
    "content": "class Solution:\n    def canFinish(self, n, P):\n        \"\"\"\n        :type n: int\n        :type P: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        indeg = [0] * n\n        edges = [[] for _ in range(n)]\n\n        for c, p in P:\n            indeg[c] += 1\n            edges[p].append(c)\n\n        queue = [i for i in range(n) if indeg[i] == 0]\n        for p in queue:\n            for c in edges[p]:\n                indeg[c] -= 1\n                if indeg[c] == 0:\n                    queue.append(c)\n\n        return len(queue) == n\n"
  },
  {
    "path": "lintcode/616_course_schedule_ii.py",
    "content": "class Solution:\n    def findOrder(self, n, prerequisites):\n        \"\"\"\n        :type n: int\n        :type prerequisites: list[list[int]]\n        :rtype: list[int]\n        \"\"\"\n        ans = []\n\n        if not n:\n            return ans\n\n        indeg = [0] * n\n        edges = [[] for _ in range(n)]\n\n        for c, p in prerequisites:\n            indeg[c] += 1\n            edges[p].append(c)\n\n        queue = [c for c in range(n) if indeg[c] == 0]\n\n        for p in queue:\n            for c in edges[p]:\n                indeg[c] -= 1\n\n                if indeg[c] == 0:\n                    queue.append(c)\n\n        if len(queue) != n:\n            return []\n\n        return queue\n"
  },
  {
    "path": "lintcode/617_maximum_average_subarray.py",
    "content": "\"\"\"\nREF: https://stackoverflow.com/questions/13093602/finding-subarray-with-maximum-sum-number-of-elements#answer-13094527\n\nYou can use binary search.\n\nFor a searched value `avg`, consider the array `B[i] = A[i] - avg`.\nNow find the maximum sum subarray of length at least `k`.\n\nThis works because the average of a subarray of length `k` is\n\n`(A[i] + ... + A[i + k - 1]) / k`.\n\nSo we have:\n`(A[i] + ... + A[i + k - 1]) / k >= avg`\n=> `A[i] + ... + A[i + k - 1] >= avg * k`\n=> `(A[i] - avg) + ... + (A[i + k - 1] - avg) >= 0`\n\nSo, if you binary search for the average, by substracting it from each element,\n\nif you can find a non-negative sum subarray of length at least k,\nthat is, find the maximum one and check if it's non-negative.\n\nthen avg is a valid answer,\ncontinue to search in [avg, max_avg] to see if you can find a better one.\nIf not, reduce search to [0, avg].\n\n       ans-2c ans-c ans ans+c ans+2c\nvalid    T      T    T    F     F\n\"\"\"\n\n\nclass Solution:\n    def maxAverage(self, nums, k):\n        \"\"\"\n        :type nums: list[int]\n        :type k: int\n        :rtype: float\n        \"\"\"\n        if not nums or not k:\n            return 0.0\n\n        EPS = 1e-5\n\n        # ans MUST between `min(nums)` and `max(nums)`\n        left = right = nums[0]\n        for num in nums:\n            if num < left:\n                left = num\n            if num > right:\n                right = num\n\n        # prefix sum\n        s = [0] * (len(nums) + 1)\n        while right - left > EPS:\n            mid = (left + right) / 2.0\n\n            if self.is_valid(nums, k, mid, s):\n                left = mid\n            else:\n                right = mid\n\n        return left\n\n    def is_valid(self, nums, k, mid, s):\n        s[0] = smin = 0\n\n        for i in range(1, len(nums) + 1):\n            s[i] = s[i - 1] + nums[i - 1] - mid\n\n            if i < k:\n                continue\n\n            \"\"\"\n            if there is a non-negative sum subarray of length at least k\n            => it's valid even if just only one, return True immediately\n            \"\"\"\n            if s[i] >= smin:  # s[i] - smin >= 0\n                return True\n\n            if s[i - k + 1] < smin:\n                smin = s[i - k + 1]\n\n        return False\n"
  },
  {
    "path": "lintcode/618_search_graph_nodes.py",
    "content": "\"\"\"\nTest Case:\n\n{1}\n[0]\n1\n0\n\"\"\"\n\"\"\"\nDefinition for a undirected graph node\nclass UndirectedGraphNode:\n    def __init__(self, x):\n        self.label = x\n        self.neighbors = []\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param {UndirectedGraphNode[]} graph a list of undirected graph node\n    @param {dict} values a dict, <UndirectedGraphNode, (int)value>\n    @param {UndirectedGraphNode} node an Undirected graph node\n    @param {int} target an integer\n    @return {UndirectedGraphNode} a node\n    \"\"\"\n    def searchNode(self, graph, values, node, target):\n        if not graph:\n            return\n\n        queue = [node]\n        visited = {_node: False for _node in graph}\n\n        for _node in queue:\n            visited[_node] = True\n            if values[_node] == target:\n                return _node\n            for _neighbor in _node.neighbors:\n                if not visited[_neighbor]:\n                    queue.append(_neighbor)\n"
  },
  {
    "path": "lintcode/619_binary_tree_longest_consecutive_sequence_iii.py",
    "content": "\"\"\"\nThe path could be start and end at any node in the tree\n\n\nDefinition for a multi tree node.\nclass MultiTreeNode(object):\n    def __init__(self, x):\n        self.val = x\n        children = [] # children is a list of MultiTreeNode\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    Bottom Up\n    \"\"\"\n    def longestConsecutive3(self, root):\n        \"\"\"\n        :type root: MultiTreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        return self.divide_conquer(root)[0]\n\n    def divide_conquer(self, node):\n        if not node:\n            return 0, 0, 0\n\n        size = 1\n        up = down = 0\n\n        for child in node.children:\n            if not child:\n                continue\n\n            _size, _up, _down = self.divide_conquer(child)\n\n            if child.val + 1 == node.val and _up + 1 > up:\n                up = _up + 1\n\n            if child.val - 1 == node.val and _down + 1 > down:\n                down = _down + 1\n\n            if _size > size:\n                size = _size\n\n        if up + down + 1 > size:\n            size = up + down + 1\n\n        return size, up, down\n"
  },
  {
    "path": "lintcode/61_search_for_a_range.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an integer sorted array\n    @param: target: an integer to be inserted\n    @return: a list of length 2, [index1, index2]\n    \"\"\"\n    def searchRange(self, A, target):\n        NOT_FOUND = [-1, -1]\n\n        if not A:\n            return NOT_FOUND\n\n        n = len(A)\n\n        left, mid, right = 0, 0, n - 1\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] < target:\n                left = mid\n            else:\n                right = mid\n\n        start = left if A[left] == target else right\n\n        left, mid, right = 0, 0, n - 1\n        while left + 1 < right:\n            mid = left + (right - left) // 2\n            if A[mid] <= target:\n                left = mid\n            else:\n                right = mid\n\n        end = right if A[right] == target else left\n\n        if start <= end:\n            return [start, end]\n\n        return NOT_FOUND\n"
  },
  {
    "path": "lintcode/620_maximum_subarray_iv.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: an array of integer\n    @param: k: an integer\n    @return: the largest sum\n    \"\"\"\n    def maxSubarray4(self, A, k):\n        if not A:\n            return 0\n        n = len(A)\n        if n < k:\n            return 0\n\n        ans = float('-inf')\n        Smin = 0\n        S = [0] * (n + 1)\n\n        for i in range(1, n + 1):\n            S[i] = S[i - 1] + A[i - 1]\n\n            \"\"\"\n            in prefix sum, `i` means the size,\n            and ignoring that iteration if `i` < `k`\n            \"\"\"\n            if i < k:\n                continue\n\n            if S[i] - Smin > ans:\n                ans = S[i] - Smin\n\n            \"\"\"\n            to get the segment sum of `k` children and ended at `i`\n            => [i - k + 1, i]\n            \"\"\"\n            if S[i - k + 1] < Smin:\n                Smin = S[i - k + 1]\n\n        return ans\n"
  },
  {
    "path": "lintcode/621_maximum_subarray_v.py",
    "content": "\"\"\"\nmain concept:\n\nsince the size of subarrays in [k1, k2] of `A`\nso when the iteration ended at `i` in `S`\nthe start index should be in [i - k2, i - k1] in `S`,\nthat is, [i - k2 + 1, i - k1 + 1] in `A`\nand then we using a queue to record the minimum of the index\n\nthe ans is `S[i] - S[queue[0]]`\n\"\"\"\nfrom collections import deque\n\n\nclass Solution:\n    \"\"\"\n    @param: A: an array of integers\n    @param: k1: An integer\n    @param: k2: An integer\n    @return: the largest sum\n    \"\"\"\n    def maxSubarray5(self, A, k1, k2):\n        if not A or not k2 or len(A) < k1:\n            return 0\n\n        n = len(A)\n        S = [0] * (n + 1)\n        queue = deque()\n        ans = float('-inf')\n\n        for i in range(1, n + 1):\n            S[i] = S[i - 1] + A[i - 1]\n\n            \"\"\"\n            if the minimum of index is less than `i - k2`\n            kicked it off\n            \"\"\"\n            if queue and queue[0] < i - k2:\n                queue.popleft()\n\n            if i < k1:\n                continue\n\n            \"\"\"\n            if the recent children are great than `S[i - k1]`,\n            means the min sum is impossible to occur here\n            \"\"\"\n            while queue and S[queue[-1]] > S[i - k1]:\n                queue.pop()\n            queue.append(i - k1)\n\n            if queue and S[i] - S[queue[0]] > ans:\n                ans = S[i] - S[queue[0]]\n\n        return ans\n"
  },
  {
    "path": "lintcode/622_frog_jump.py",
    "content": "\"\"\"\nBFS\n\"\"\"\nclass Solution:\n    def canCross(self, stones):\n        \"\"\"\n        :type stones: List[int]\n        :rtype: bool\n        \"\"\"\n        if not stones:\n            return False\n        if len(stones) < 2:\n            return True\n        if stones[1] != 1:\n            return False\n\n        xs = set(stones)  # to check in O(1)\n        queue = [(stones[0], 0)]\n        visited = set(queue)\n\n        for pos, k in queue:\n            for x in (k - 1, k, k + 1):\n                if x <= 0 or pos + x not in xs:\n                    continue\n                if (pos + x, x) in visited:\n                    continue\n                if pos + x == stones[-1]:\n                    return True\n\n                visited.add((pos + x, x))\n                queue.append((pos + x, x))\n\n        return False\n\n\n\"\"\"\nDP\n\"\"\"\nclass Solution:\n    def canCross(self, stones):\n        \"\"\"\n        :type stones: List[int]\n        :rtype: bool\n        \"\"\"\n        if not stones:\n            return False\n        if len(stones) < 2:\n            return True\n        if stones[1] != 1:\n            return False\n\n        dp = {pos: set() for pos in stones}\n        dp[stones[0]].add(0)\n\n        for pos in stones:\n            for k in dp[pos]:\n                # k - 1 > 0\n                if k > 1 and pos + k - 1 in dp:\n                    dp[pos + k - 1].add(k - 1)\n                if pos + k in dp:\n                    dp[pos + k].add(k)\n                if pos + k + 1 in dp:\n                    dp[pos + k + 1].add(k + 1)\n\n        return bool(dp[stones[-1]])\n"
  },
  {
    "path": "lintcode/623_k_edit_distance.py",
    "content": "class TrieNode:\n    def __init__(self):\n        self.end_of = None\n        self.children = {}\n\n\nclass Trie:\n    def __init__(self):\n        self.root = TrieNode()\n\n    def put(self, word):\n        if not isinstance(word, str):\n            return\n\n        node = self.root\n\n        for c in word:\n            if c not in node.children:\n                node.children[c] = TrieNode()\n\n            node = node.children[c]\n\n        node.end_of = word\n\n\nclass Solution:\n    def kDistance(self, words, target, k):\n        \"\"\"\n        :type words: list[str]\n        :type target: str\n        :type k: int\n        :rtype: list[str]\n        \"\"\"\n        trie = Trie()\n\n        for word in words:\n            trie.put(word)\n\n        ans = []\n        dp = [i for i in range(len(target) + 1)]\n\n        self.dfs(trie.root, k, target, ans, dp)\n\n        return ans\n\n    def dfs(self, node, k, target, ans, pre):\n        n = len(target)\n\n        if node.end_of is not None and pre[n] <= k:\n            ans.append(node.end_of)\n\n        dp = [0] * (n + 1)\n\n        for c in node.children:\n            dp[0] = pre[0] + 1\n\n            for i in range(1, n + 1):\n                if target[i - 1] == c:\n                    dp[i] = min(\n                        dp[i - 1] + 1,\n                        pre[i] + 1,\n                        pre[i - 1]\n                    )\n                else:\n                    dp[i] = min(\n                        dp[i - 1] + 1,\n                        pre[i] + 1,\n                        pre[i - 1] + 1\n                    )\n\n            self.dfs(node.children[c], k, target, ans, dp)\n"
  },
  {
    "path": "lintcode/624_remove_substrings.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: a string\n    @param: D: a set of n substrings\n    @return: the minimum length\n    \"\"\"\n    def minLength(self, s, D):\n        if not s:\n            return 0\n\n        _min = len(s)\n        queue = [s]\n        visited = set([s])\n\n        \"\"\"\n        bfs\n                 s\n          /----/---\\----\\\n        s-d1 s-d2 s-d3 s-d4\n        ...  ...  ...  ...\n        \"\"\"\n        for s in queue:\n            for d in D:\n                found = s.find(d)\n                while found != -1:\n                    _s = s[:found] + s[found + len(d):]\n                    found = s.find(d, found + 1)\n\n                    if _s in visited:\n                        continue\n\n                    if len(_s) < _min:\n                        _min = len(_s)\n\n                    queue.append(_s)\n                    visited.add(_s)\n\n        return _min\n"
  },
  {
    "path": "lintcode/625_partition_array_ii.py",
    "content": "\"\"\"\nRainbow Sort\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an integer array\n    @param: low: An integer\n    @param: high: An integer\n    @return:\n    \"\"\"\n    def partition2(self, A, low, high):\n        if not A:\n            return\n\n        left, right = 0, len(A) - 1\n        i = 0\n\n        while i < right:\n            if A[i] < low:\n                A[left], A[i] = A[i], A[left]\n                left += 1\n                i += 1\n            elif A[i] > high:\n                A[right], A[i] = A[i], A[right]\n                right -= 1\n            else:\n                i += 1\n"
  },
  {
    "path": "lintcode/630_knight_shortest_path_ii.py",
    "content": "\"\"\"\nDFS\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: G: a chessboard included 0 and 1\n    @return: the shortest path\n    \"\"\"\n    def shortestPath2(self, G):\n        NOT_FOUND = -1\n        if not G or not G[0] or G[0][0] == 1:\n            return NOT_FOUND\n\n        V = (\n            (-1,  2),\n            ( 1,  2),\n            (-2,  1),\n            ( 2,  1),\n        )\n        m, n = len(G), len(G[0])\n\n        queue = [(0, 0)]\n        turns = {(0, 0): 0}\n        for x, y in queue:\n            for dx, dy in V:\n                _x = x + dx\n                _y = y + dy\n                if 0 <= _x < m and 0 <= _y < n and G[_x][_y] == 0:\n                    if (_x, _y) in turns:\n                        continue\n\n                    turns[_x, _y] = turns[x, y] + 1\n\n                    if _x == m - 1 and _y == n - 1:\n                        return turns[_x, _y]\n\n                    queue.append((_x, _y))\n\n        return NOT_FOUND\n\n\n\"\"\"\nDP\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: G: a chessboard included 0 and 1\n    @return: the shortest path\n    \"\"\"\n    def shortestPath2(self, G):\n        if not G or not G[0] or G[0][0] == 1:\n            return -1\n\n        INFINITY = float('inf')\n\n        m, n = len(G), len(G[0])\n        dp = [[INFINITY] * 3 for _ in range(m)]\n        pre2 = pre1 = curr = 0\n        dp[0][curr] = 0\n\n        \"\"\"\n        x and y is changed since its need from left to right\n        \"\"\"\n        for y in range(1, n):\n            pre2, pre1 = pre1, curr\n            curr = y % 3\n            for x in range(m):\n                dp[x][curr] = INFINITY\n\n                if G[x][y] == 1:\n                    continue\n\n                if (x >= 2 and y >= 1 and dp[x - 2][pre1] < INFINITY and\n                    dp[x - 2][pre1] + 1 < dp[x][curr]):\n                    dp[x][curr] = dp[x - 2][pre1] + 1\n\n                if (x >= 1 and y >= 2 and dp[x - 1][pre2] < INFINITY and\n                    dp[x - 1][pre2] + 1 < dp[x][curr]):\n                    dp[x][curr] = dp[x - 1][pre2] + 1\n\n                if (x + 1 < m and y >= 2 and dp[x + 1][pre2] < INFINITY and\n                    dp[x + 1][pre2] + 1 < dp[x][curr]):\n                    dp[x][curr] = dp[x + 1][pre2] + 1\n\n                if (x + 2 < m and y >= 1 and dp[x + 2][pre1] < INFINITY and\n                    dp[x + 2][pre1] + 1 < dp[x][curr]):\n                    dp[x][curr] = dp[x + 2][pre1] + 1\n\n        return dp[m - 1][curr] if dp[m - 1][curr] < INFINITY else -1\n"
  },
  {
    "path": "lintcode/633_find_the_duplicate_number.py",
    "content": "\"\"\"\nBinary Searching\n\n`a`: the duplicated num\n`cnt(b)`: the cnt of children less than or equal `b`\n\nfor each `num < a`: `cnt(num) == num`\nfor each `num >= a`: `cnt(num) > num`\n\"\"\"\nclass Solution:\n    def findDuplicate(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        if not A:\n            return -1\n\n        left, right = 1, len(A) - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if self.after_dup(A, mid):\n                right = mid\n            else:\n                left = mid\n\n        if self.after_dup(A, left):\n            return left\n        if self.after_dup(A, right):\n            return right\n        return -1\n\n    def after_dup(self, A, mid):\n        cnt = 0\n\n        for a in A:\n            if a <= mid:\n                cnt += 1\n            if cnt > mid:\n                return True\n\n        return False\n\n\n\"\"\"\nFloyd Circle Detection\n\nexample: [5,4,4,3,2,1]\n\ni  0, 1, 2, 3, 4, 5\na  5, 4, 4, 3, 2, 1\n-------------------\n   s              f\n      f           s\n      s  f\n         f     s\n         sf\n-------------------\n   f     s\n               s  f\n      f  s\n               sf\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: an array containing n + 1 integers which is between 1 and n\n    @return: the duplicate one\n    \"\"\"\n    def findDuplicate(self, A):\n        if not A:\n            return -1\n\n        slow = A[0]\n        fast = A[A[0]]\n\n        while slow != fast:\n            slow = A[slow]\n            fast = A[A[fast]]\n\n        fast = 0\n\n        while slow != fast:\n            slow = A[slow]\n            fast = A[fast]\n\n        return slow\n"
  },
  {
    "path": "lintcode/634_word_squares.py",
    "content": "\"\"\"\nTrie + DFS\n\"\"\"\n\n\n\n\"\"\"\nTLE: DFS\n\"\"\"\nclass Solution:\n    def wordSquares(self, words):\n        \"\"\"\n        :type words: list[str]\n        :rtype: list[list[str]]\n        \"\"\"\n        ans = []\n        if not words:\n            return ans\n\n        self.dfs(words, len(words[0]), ans, [])\n\n        return ans\n\n    def dfs(self, words, n, ans, path):\n        if (len(path) == n and\n            self.is_valid(path)):\n            ans.append(path[:])\n            return\n\n        if len(path) >= n:\n            return\n\n        for i in range(len(words)):\n            path.append(words[i])\n            self.dfs(words, n, ans, path)\n            path.pop()\n\n    def is_valid(self, path):\n        if not path or len(path) != len(path[0]):\n            return False\n\n        for i in range(1, len(path)):\n            for j in range(i):\n                if path[i][j] != path[j][i]:\n                    return False\n\n        return True\n"
  },
  {
    "path": "lintcode/635_boggle_game.py",
    "content": "class TrieNode:\n    def __init__(self):\n        self.children = {}\n        self.end_of = None\n\n\nclass Solution:\n    def boggleGame(self, board, words):\n        \"\"\"\n        :type board: list[list[str]]\n        :type words: list[str]\n        :rtype: int\n        \"\"\"\n        self.ans = 0\n\n        if not board or not board[0]:\n            return self.ans\n\n\n        root = TrieNode()\n\n        for word in words:\n            self.put(root, word)\n\n\n        m, n = len(board), len(board[0])\n        visited = set()\n\n        for x in range(m):\n            for y in range(n):\n                self.dfs(board, x, y, root, visited, 0)\n\n\n        return self.ans\n\n    def dfs(self, board, i, j, root, visited, cnt):\n        m, n = len(board), len(board[0])\n\n        for x in range(i, m):\n            for y in range(j, n):\n                next_words = []\n                self.find_next_words(board, x, y, visited, cnt, root, next_words, [])\n\n                for pos in next_words:\n                    for p in pos:\n                        visited.add(p)\n\n                    self.dfs(board, x, y, root, visited, cnt + 1)\n\n                    for p in pos:\n                        visited.discard(p)\n\n            j = 0\n\n    def find_next_words(self, board, x, y, visited, cnt, node, next_words, path):\n        if (x, y) in visited or board[x][y] not in node.children:\n            return\n\n        m, n = len(board), len(board[0])\n        node = node.children[board[x][y]]\n\n        path.append((x, y))\n        visited.add((x, y))\n\n        if node.end_of is not None:\n            next_words.append(path[:])\n            self.ans = max(self.ans, cnt + 1)\n        else:\n            for dx, dy in (\n                (-1, 0), (1, 0),\n                (0, -1), (0, 1),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n\n                self.find_next_words(board, _x, _y, visited, cnt, node, next_words, path)\n\n        path.pop()\n        visited.discard((x, y))\n\n    def put(self, root, word):\n        node = root\n\n        for c in word:\n            if c not in node.children:\n                node.children[c] = TrieNode()\n\n            node = node.children[c]\n\n        node.end_of = word\n"
  },
  {
    "path": "lintcode/636_132_pattern.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: a list of n integers\n    @return: true if there is a 132 pattern or false\n    \"\"\"\n    def find132pattern(self, A):\n        if not A:\n            return False\n\n        stack = [float('-inf')]\n        for i in range(len(A) - 1, -1, -1):\n            if A[i] < stack[-1]:\n                return True\n\n            v = None\n            while stack and A[i] > stack[-1]:\n                v = stack.pop()\n\n            stack.append(A[i])\n\n            if v is not None:\n                stack.append(v)\n\n        return False\n"
  },
  {
    "path": "lintcode/646_first_position_unique_character.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: a string\n    @return: it's index\n    \"\"\"\n    def firstUniqChar(self, s):\n        if not s:\n            return -1\n\n        D = {}\n        for c in s:\n            D[c] = D.get(c, 0) + 1\n\n        i = 0\n        for c in s:\n            if D[c] == 1:\n                return i\n            i += 1\n\n        return -1\n"
  },
  {
    "path": "lintcode/647_substring_anagrams.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/92007/\n\"\"\"\n\n\nclass Solution:\n    def findAnagrams(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: List[int]\n        \"\"\"\n        ans = []\n        if not s or not t or len(t) > len(s):\n            return ans\n\n        F = {}\n        for c in t:\n            F[c] = F.get(c, 0) + 1\n\n        n, m, cnt = len(s), len(t), len(F)\n        left = right = 0\n\n        while right < n:\n            if s[right] in F:\n                F[s[right]] -= 1\n                if F[s[right]] == 0:\n                    cnt -= 1\n\n            right += 1\n\n            while cnt == 0:\n                if s[left] in F:\n                    F[s[left]] += 1\n                    if F[s[left]] == 1:\n                        cnt += 1\n\n                if right - left == m:\n                    ans.append(left)\n\n                left += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/64_merge_sorted_array.py",
    "content": "class Solution:\n    def mergeSortedArray(self, a, m, b, n):\n        \"\"\"\n        :type a: List[int]\n        :type m: int\n        :type b: List[int]\n        :type n: int\n        :rtype: void Do not return anything, modify nums1 in-place instead.\n        \"\"\"\n        i, j = m - 1, n - 1\n        k = m + n - 1\n\n        while i >= 0 and j >= 0:\n            if a[i] > b[j]:\n                a[k] = a[i]\n                i -= 1\n            else:\n                a[k] = b[j]\n                j -= 1\n            k -= 1\n\n        while j >= 0:\n            a[k] = b[j]\n            j -= 1\n            k -= 1\n"
  },
  {
    "path": "lintcode/654_sparse_matrix_multiplication.py",
    "content": "class Solution:\n    \"\"\"\n    @param A: a sparse matrix\n    @param B: a sparse matrix\n    @return: the result of A * B\n    \"\"\"\n    def multiply(self, A, B):\n        if not A or not B or len(A[0]) != len(B):\n            return []\n\n        m, n = len(A), len(B[0])\n        l = len(B)\n\n        ans = [[0] * n for _ in range(m)]\n\n        for i in range(m):\n            for j in range(n):\n                for k in range(l):\n                    ans[i][j] += A[i][k] * B[k][j]\n\n        return ans\n"
  },
  {
    "path": "lintcode/655_big_integer_addition.py",
    "content": "class Solution:\n    def addStrings(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: str\n        \"\"\"\n        if not a and not b:\n            return ''\n        if not a:\n            return b\n        if not b:\n            return a\n\n        m, n = len(a), len(b)\n        idx = max(m, n)\n        ans = [''] * (idx + 1)\n\n        i = m - 1\n        j = n - 1\n        carry = 0\n        zero = ord('0')\n\n        while i >= 0 and j >= 0:\n            carry += ord(a[i]) + ord(b[j]) - 2 * zero\n            ans[idx] = str(carry % 10)\n            carry //= 10\n            idx -= 1\n            i -= 1\n            j -= 1\n\n        while i >= 0:\n            carry += ord(a[i]) - zero\n            ans[idx] = str(carry % 10)\n            carry //= 10\n            idx -= 1\n            i -= 1\n\n        while j >= 0:\n            carry += ord(b[j]) - zero\n            ans[idx] = str(carry % 10)\n            carry //= 10\n            idx -= 1\n            j -= 1\n\n        if carry:\n            ans[0] = str(carry)\n        else:\n            ans = ans[1:]\n\n        return ''.join(ans)\n"
  },
  {
    "path": "lintcode/656_big_integer_multiplication.py",
    "content": "class Solution:\n    def multiply(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: str\n        \"\"\"\n        if not a or not b or a == '0' or b == '0':\n            return '0'\n\n        m, n = len(a), len(b)\n        tmp = [0] * (m + n)\n\n        for i in range(m - 1, -1, -1):\n            carry = 0\n            for j in range(n - 1, -1, -1):\n                carry += tmp[i + j + 1] + int(a[i]) * int(b[j])\n                tmp[i + j + 1] = carry % 10\n                carry //= 10\n            tmp[i] = carry\n\n        i = 0\n        while tmp[i] == 0:\n            i += 1\n\n        return ''.join([str(j) for j in tmp[i:]])\n"
  },
  {
    "path": "lintcode/65_median_of_two_sorted_arrays.py",
    "content": "\"\"\"\nHeap\n\"\"\"\nimport heapq\n\n\nclass Solution:\n    def findMedianSortedArrays(self, a, b):\n        \"\"\"\n        :type a: list\n        :type b: list\n        :rtype: float\n        \"\"\"\n        heap = []\n        n = 0\n\n        for nums in (a, b):\n            if not nums:\n                continue\n\n            n += len(nums)\n            heapq.heappush(heap, (nums[0], nums, 0))\n\n        if n == 0:\n            return 0.0\n\n        num = 0\n        for _ in range((n + 1) // 2):\n            num, nums, i = heapq.heappop(heap)\n\n            i += 1\n            if i < len(nums):\n                heapq.heappush(heap, (nums[i], nums, i))\n\n        if n & 1 == 1:\n            return num * 1.0\n\n        _num = heapq.heappop(heap)[0]\n        return (num + _num) / 2.0\n\n\n\"\"\"\nDecreasing Approaching\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: A: An integer array\n    @param: B: An integer array\n    @return: a double whose format is *.5 or *.0\n    \"\"\"\n    def findMedianSortedArrays(self, A, B):\n        n = len(A) + len(B)\n\n        median = self.find_kth(A, 0, B, 0, n // 2 + 1)\n        if n % 2 == 1:\n            return median\n\n        _median = self.find_kth(A, 0, B, 0, n // 2)\n        return (median + _median) / 2.0\n\n    def find_kth(self, A, i, B, j, k):\n        \"\"\"\n        example: A: [1, 2, 3, 4, 5, 6]\n                 B: [2, 3, 4, 5]\n\n        m + n = 10, median is `(5th + 6th) / 2`\n        the process below is to find the `6th`\n        r1/ k = 6\n            1  2 |3| 4  5  6\n            2  3 |4| 5\n            _a = _b = 2\n            a = 3, b = 4\n            a < b\n        r2/ k = 3\n           -1--2--3-|4| 5  6\n           |2| 3  4  5\n            _a = 3, _b = 0\n            a = 4, b = 2\n            a > b\n        r3/ k = 2\n           -1--2--3-|4| 5  6\n           -2-|3| 4  5\n            _a = 3, _b = 1\n            a = 4, b = 3\n            a > b\n        r4/ k = 1\n           -1--2--3-|4| 5  6\n           -2--3-|4| 5\n            since k == 1\n            return min(4, 4) = `4`\n        \"\"\"\n        if i >= len(A):\n            return B[j + k - 1]\n        if j >= len(B):\n            return A[i + k - 1]\n        if k == 1:\n            return min(A[i], B[j])\n\n        _a = i + k // 2 - 1\n        _b = j + k // 2 - 1\n        a = A[_a] if _a < len(A) else float('inf')\n        b = B[_b] if _b < len(B) else float('inf')\n\n        if a < b:\n            return self.find_kth(A, i + k // 2, B, j, k - k // 2)\n        else:\n            return self.find_kth(A, i, B, j + k // 2, k - k // 2)\n"
  },
  {
    "path": "lintcode/662_guess_number_game.py",
    "content": "\"\"\"\nThe guess API is already defined for you.\n@param num, your guess\n@return -1 if my number is lower, 1 if my number is higher, otherwise return 0\nyou can call Guess.guess(num)\n\"\"\"\n\n\nclass Solution:\n    def guessNumber(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if not n or n <= 1:\n            return 1\n\n        left, right = 1, n\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            res = Guess.guess(mid)\n\n            if res == 0:\n                return mid\n            elif res == 1:\n                left = mid\n            else:\n                right = mid\n\n        return left if Guess.guess(left) == 0 else right\n"
  },
  {
    "path": "lintcode/664_counting_bits.py",
    "content": "class Solution:\n    \"\"\"\n    @param: num: a non negative integer number\n    @return: an array represent the number of 1's in their binary\n    \"\"\"\n    def countBits(self, num):\n        if not num:\n            return [0]\n\n        upper_bound = num + 1\n        F = [0] * upper_bound\n\n        for i in range(1, upper_bound):\n            \"\"\"\n            1. `i & (i - 1)` must be less than `i`, since `0 & n` is `0`\n               => `F[i & (i - 1)]` must have been calculated\n            2. `+ 1` means the removed `1` in bit\n            \"\"\"\n            F[i] = F[i & (i - 1)] + 1\n\n        return F\n"
  },
  {
    "path": "lintcode/667_longest_palindromic_subsequence.py",
    "content": "class Solution:\n    \"\"\"\n    @param: s: the maximum length of s is 1000\n    @return: the longest palindromic subsequence's length\n    \"\"\"\n    def longestPalindromeSubseq(self, s):\n        if not s:\n            return 0\n\n        n = len(s)\n        if n == 1:\n            return 1\n\n        # `dp[i][j]` means the length of the longest subsequence\n        # included in `s[i:j+1]`\n        dp = [[0] * n for _ in range(n)]\n\n        ans = 0\n        start = end = 0\n        for end in range(n):\n            dp[end][end] = 1\n\n            if n < 1:\n                continue\n\n            start = end - 1\n            if s[start] == s[end]:\n                dp[start][end] = 2\n            else:\n                dp[start][end] = 1\n\n        for size in range(3, n + 1):\n            for start in range(n - size + 1):\n                end = start + size - 1\n\n                dp[start][end] = max(dp[start][end - 1], dp[start + 1][end])\n\n                if s[start] == s[end]:\n                    dp[start][end] = max(\n                        dp[start][end],\n                        dp[start + 1][end - 1] + 2\n                    )\n\n                if dp[start][end] > ans:\n                    ans = dp[start][end]\n\n        return ans\n"
  },
  {
    "path": "lintcode/668_ones_and_zeroes.py",
    "content": "\"\"\"\noptimized space complexity\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: strs: an array with strings include only 0 and 1\n    @param: m: An integer\n    @param: n: An integer\n    @return: find the maximum number of strings\n    \"\"\"\n    def findMaxForm(self, strs, m, n):\n        if not strs:\n            return 0\n\n        \"\"\"\n        `dp[j][k]` means the current str can be made up of\n        `j` 0s and `k` 1s\n        \"\"\"\n        dp = [[0] * (n + 1) for _ in range(m + 1)]\n\n        c0 = c1 = 0\n        for s in strs:\n            c0 = s.count('0')\n            c1 = len(s) - c0\n\n            for j in range(m, c0 - 1, -1):\n                for k in range(n, c1 - 1, -1):\n                    \"\"\"\n                    case 1: included current `strs[i - 1]`\n                    case 2: not included current `strs[i - 1]`, same as previous\n                    \"\"\"\n                    dp[j][k] = max(\n                        dp[j][k],\n                        dp[j - c0][k - c1] + 1\n                    )\n\n        return dp[m][n]\n\n\n\"\"\"\norigin\n\"\"\"\nclass Solution:\n    \"\"\"\n    @param: strs: an array with strings include only 0 and 1\n    @param: m: An integer\n    @param: n: An integer\n    @return: find the maximum number of strings\n    \"\"\"\n    def findMaxForm(self, strs, m, n):\n        if not strs:\n            return 0\n\n        l = len(strs)\n\n        \"\"\"\n        `dp[i][j][k]` means the pre- `i`th strs can be made up of\n        `j` 0s and `k` 1s\n\n        dp[0][j][k] = 0\n        \"\"\"\n        dp = [[[0] * (n + 1) for _ in range(m + 1)] for _ in range(l + 1)]\n\n        c0 = c1 = 0\n        for i in range(1, l + 1):\n            c0 = strs[i - 1].count('0')\n            c1 = len(strs[i - 1]) - c0\n\n            for j in range(m + 1):\n                for k in range(n + 1):\n                    \"\"\"\n                    case 1: included current `strs[i - 1]`\n                    \"\"\"\n                    if j >= c0 and k >= c1:\n                        dp[i][j][k] = dp[i - 1][j - c0][k - c1] + 1\n\n                    \"\"\"\n                    case 2: not included current `strs[i - 1]`, same as previous\n                    \"\"\"\n                    if dp[i - 1][j][k] > dp[i][j][k]:\n                        dp[i][j][k] = dp[i - 1][j][k]\n\n        return dp[l][m][n]\n"
  },
  {
    "path": "lintcode/669_coin_change.py",
    "content": "class Solution:\n    \"\"\"\n    BFS\n    \"\"\"\n    def coinChange(self, coins, amount):\n        \"\"\"\n        :type coins: List[int]\n        :type amount: int\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not coins or not amount:\n            return ans\n\n        queue, _queue = [0], []\n        visited = set(queue)\n\n        while queue:\n            ans += 1\n\n            for a in queue:\n                for c in coins:\n                    _a = a + c\n\n                    if _a == amount:\n                        return ans\n\n                    if _a > amount or _a in visited:\n                        continue\n\n                    visited.add(_a)\n                    _queue.append(_a)\n\n            queue, _queue = _queue, []\n\n        return -1\n\n\nclass Solution:\n    \"\"\"\n    DP: TLE\n    \"\"\"\n    def coinChange(self, coins, amount):\n        \"\"\"\n        :type coins: List[int]\n        :type amount: int\n        :rtype: int\n        \"\"\"\n        if not coins or not amount:\n            return 0\n\n        INF = float('inf')\n        dp = [INF] * (amount + 1)\n        dp[0] = 0\n\n        for c in coins:\n            for a in range(c, amount + 1):\n                # if a < c: continue\n                dp[a] = min(dp[a], dp[a - c] + 1)\n\n        return dp[amount] if dp[amount] < INF else -1\n"
  },
  {
    "path": "lintcode/66_binary_tree_preorder_traversal.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: A Tree\n    @return: Preorder in ArrayList which contains node values.\n    \"\"\"\n    def preorderTraversal(self, root):\n        ans = []\n        if not root:\n            return ans\n        self._traversal(root, ans)\n        return ans\n\n    def _traversal(self, node, res):\n        if not node:\n            return\n\n        res.append(node.val)\n        self._traversal(node.left, res)\n        self._traversal(node.right, res)\n"
  },
  {
    "path": "lintcode/676_decode_ways_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param s: a message being encoded\n    @return: an integer\n    \"\"\"\n    def numDecodings(self, s):\n        if not s or s == '0':\n            return 0\n\n        n = len(s)\n        MOD = 10 ** 9 + 7\n\n        dp = [0] * (n + 1)\n        dp[0] = 1\n\n        if s[0] == '*':\n            dp[1] = 9  # 9 * dp[0]\n        elif s[0] != '0':\n            dp[1] = 1  # dp[0]\n\n        for i in range(2, n + 1):\n            if s[i - 1] == '*':\n                dp[i] += 9 * dp[i - 1]\n\n                if s[i - 2] == '*':\n                    dp[i] += 15 * dp[i - 2]\n                elif s[i - 2] == '1':\n                    dp[i] += 9 * dp[i - 2]\n                elif s[i - 2] == '2':\n                    dp[i] += 6 * dp[i - 2]\n\n                dp[i] %= MOD\n                continue\n\n            if s[i - 1] != '0':\n                dp[i] += dp[i - 1]\n\n            if s[i - 2] == '*':\n                if int(s[i - 1]) <= 6:\n                    dp[i] += 2 * dp[i - 2]\n                else:\n                    dp[i] += dp[i - 2]\n            elif 10 <= int(s[i - 2:i]) <= 26:\n                dp[i] += dp[i - 2]\n\n            dp[i] %= MOD\n\n        return dp[n]\n"
  },
  {
    "path": "lintcode/67_binary_tree_inorder_traversal.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: A Tree\n    @return: Inorder in ArrayList which contains node values.\n    \"\"\"\n    def inorderTraversal(self, root):\n        ans = []\n        if not root:\n            return ans\n        self._traversal(root, ans)\n        return ans\n\n    def _traversal(self, node, res):\n        if not node:\n            return\n\n        self._traversal(node.left, res)\n        res.append(node.val)\n        self._traversal(node.right, res)\n"
  },
  {
    "path": "lintcode/689_two_sum_bst_edtion.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: : the root of tree\n    @param: : the target sum\n    @return: two numbers from tree which sum is n\n    \"\"\"\n    def twoSum(self, root, n):\n        self.left = self.right = None\n        self.head = self.tail = root\n\n        self.pre()\n        self.nxt()\n\n        while self.left != self.right:\n            _sum = self.left.val + self.right.val\n\n            if _sum == n:\n                return [self.left.val, self.right.val]\n\n            if _sum < n:\n                self.nxt()\n            else:\n                self.pre()\n\n    def pre(self):\n        while self.tail:\n            cur = self.tail.right\n\n            if cur and cur != self.right:\n                while cur.left and cur.left != self.tail:\n                    cur = cur.left\n\n                if cur.left == self.tail:\n                    self.right = self.tail\n\n                    cur.left = None\n                    self.tail = self.tail.left\n                    break\n                else:\n                    cur.left = self.tail\n                    self.tail = self.tail.right\n            else:\n                self.right = self.tail\n                self.tail = self.tail.left\n                break\n\n    def nxt(self):\n        while self.head:\n            cur = self.head.left\n\n            if cur and cur != self.left:\n                while cur.right and cur.right != self.head:\n                    cur = cur.right\n\n                if cur.right == self.head:\n                    self.left = self.head\n\n                    cur.right = None\n                    self.head = self.head.right\n                    break\n                else:\n                    cur.right = self.head\n                    self.head = self.head.left\n            else:\n                self.left = self.head\n                self.head = self.head.right\n                break\n"
  },
  {
    "path": "lintcode/68_binary_tree_postorder_traversal.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: A Tree\n    @return: Postorder in ArrayList which contains node values.\n    \"\"\"\n    def postorderTraversal(self, root):\n        ans = []\n        if not root:\n            return ans\n\n        stack = []\n        node = last_visit = root\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack[-1]\n\n            if (not node.right or\n                last_visit is node.right):\n\n                stack.pop()\n\n                ans.append(node.val)\n                last_visit = node\n                node = None\n            else:\n                node = node.right\n\n        return ans\n"
  },
  {
    "path": "lintcode/69_binary_tree_level_order_traversal.py",
    "content": "\"\"\"\nMain Concept:\n1. Use `_queue` to collect node in current level\n2. Use `level_values` to collect the val of node in current level\n3. After traverse the current level,\n   append `level_values` to answer\n   and reset `queue` as `_queue`\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def levelOrder(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n\n        if not root:\n            return ans\n\n        queue, _queue = [root], []\n\n        while queue:\n            ans.append([])\n\n            for node in queue:\n                if node.left:\n                    _queue.append(node.left)\n                if node.right:\n                    _queue.append(node.right)\n                ans[-1].append(node.val)\n\n            queue, _queue = _queue, []\n\n        return ans\n"
  },
  {
    "path": "lintcode/6_merge_two_sorted_arrays.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: sorted integer array A\n    @param: B: sorted integer array B\n    @return: A new sorted integer array\n    \"\"\"\n    def mergeSortedArray(self, A, B):\n        if not A:\n            return B\n        if not B:\n            return A\n\n        m, n = len(A), len(B)\n        ans = [0] * (m + n)\n\n        i = j = index = 0\n        while i < m and j < n:\n            if A[i] < B[j]:\n                ans[index] = A[i]\n                i += 1\n            else:\n                ans[index] = B[j]\n                j += 1\n            index += 1\n\n        while i < m:\n            ans[index] = A[i]\n            i += 1\n            index += 1\n\n        while j < n:\n            ans[index] = B[j]\n            j += 1\n            index += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/70_binary_tree_level_order_traversal_ii.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: A tree\n    @return: buttom-up level order a list of lists of integer\n    \"\"\"\n    def levelOrderBottom(self, root):\n        ans = []\n        if not root:\n            return ans\n\n        preorder = [(root, 1)]\n        self.dfs(root, ans, preorder, 0)\n\n        \"\"\"\n        cannot do append in dfs,\n        since it may be the deepest node is at right child\n        \"\"\"\n        height = len(ans)\n        for node, level in preorder:\n            ans[height - level].append(node.val)\n\n        return ans\n\n    def dfs(self, node, ans, preorder, parent_at):\n        if len(ans) < preorder[parent_at][1]:\n            ans.append([])\n\n        depth = preorder[parent_at][1] + 1\n\n        if node.left:\n            preorder.append((node.left, depth))\n            self.dfs(node.left, ans, preorder, len(preorder) - 1)\n\n        if node.right:\n            preorder.append((node.right, depth))\n            self.dfs(node.right, ans, preorder, len(preorder) - 1)\n"
  },
  {
    "path": "lintcode/717_tree_longest_path_with_same_value.py",
    "content": "\"\"\"\nREF: https://blog.csdn.net/zhaohengchuan/article/details/78833501\n\"\"\"\n\n\nclass Solution:\n    def LongestPathWithSameValue(self, a, e):\n        \"\"\"\n        :type a: list[int]\n        :type e: list[int]\n        :rtype: int\n        \"\"\"\n        if not a or len(a) <= 1:\n            return 0\n\n        neibs = [[] for _ in range(len(a) + 1)]  # neighbors\n\n        # to build the node connection\n        for i in range(0, len(e), 2):\n            neibs[e[i]].append(e[i + 1])\n            neibs[e[i + 1]].append(e[i])\n\n        self.ans = 0\n        res = self.dfs(0, 1, a, neibs)\n\n        return max(self.ans, res)\n\n    def dfs(self, root, curr, a, neibs):\n        tmp = []\n\n        for neib in neibs[curr]:\n            # ignore if the neib is curr's parent\n            if neib == root:\n                continue\n\n            res = self.dfs(curr, neib, a, neibs)\n\n            # incr the res and append to tmp\n            # if both `neib` and `curr` have same value\n            if a[neib - 1] == a[curr - 1]:\n                tmp.append(res + 1)\n\n        # to prevent len(tmp) == 0\n        tmp.extend((0, 0))\n        tmp.sort(reverse=True)\n\n        self.ans = max(self.ans, tmp[0] + tmp[1])\n\n        return tmp[0]\n"
  },
  {
    "path": "lintcode/718_repeat_string.py",
    "content": "class Solution:\n    def repeatedString(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: int\n        \"\"\"\n        if len(b) <= len(a) and b in a:\n            return 1\n        if not a or not b:\n            return -1\n\n        ans = b.count(a)\n        c = b.split(a)\n\n        if c[0] and a.endswith(c[0]):\n            ans += 1\n\n        if c[-1] and a.startswith(c[-1]):\n            ans += 1\n\n        return ans if a.startswith(c[-1]) and a.endswith(c[0]) else -1\n"
  },
  {
    "path": "lintcode/71_binary_tree_zigzag_level_order_traversal.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: A Tree\n    @return: A list of lists of integer include the zigzag level order traversal of its nodes' values.\n    \"\"\"\n    def zigzagLevelOrder(self, root):\n        ans = []\n        if not root:\n            return ans\n\n        queue = [root]\n        while queue:\n            _queue = []\n            ans.append([])\n\n            for node in queue:\n                if node.left:\n                    _queue.append(node.left)\n                if node.right:\n                    _queue.append(node.right)\n\n                ans[-1].append(node.val)\n\n            if len(ans) % 2 == 0:\n                ans[-1].reverse()\n\n            queue = _queue\n\n        return ans\n"
  },
  {
    "path": "lintcode/724_minimum_partition.py",
    "content": "class Solution:\n    def findMin(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n\n        target = sum(nums)\n        dp = [False] * (target + 1)\n        dp[0] = True\n\n        ans = float('inf')\n\n        for num in nums:\n            for i in range(target, num - 1, -1):\n                dp[i] = dp[i] or dp[i - num]\n\n                if dp[i]:\n                    ans = min(\n                        ans,\n                        abs(target - i * 2)\n                    )\n\n        return ans\n"
  },
  {
    "path": "lintcode/725_boolean_parenthesization.py",
    "content": "\"\"\"\nREF: https://blog.csdn.net/zhaohengchuan/article/details/78937943\n\"\"\"\n\n\nclass Solution:\n    def countParenth(self, symb, oper):\n        \"\"\"\n        :type symb: list[str]\n        :type oper: list[str]\n        :rtype: int\n        \"\"\"\n        if not symb or not oper:\n            return 0\n\n        n = len(symb)\n\n        \"\"\"\n        `t[l][r]` means the ways to evaluate True in `symb[i:j]`\n        \"\"\"\n        t = [[0] * n for _ in range(n)]\n        f = [[0] * n for _ in range(n)]\n\n        for i in range(n):\n            if symb[i] == 'T':\n                t[i][i] = 1\n            else:\n                f[i][i] = 1\n\n        for r in range(n):\n            for l in range(r - 1, -1, -1):\n                t[l][r] = 0\n                f[l][r] = 0\n\n                for i in range(l, r):\n                    if oper[i] == '&':\n                        t[l][r] += t[l][i] * t[i + 1][r]\n                        f[l][r] += (\n                            (t[l][i] + f[l][i]) *\n                            (t[i + 1][r] + f[i + 1][r]) -\n                            t[l][i] * t[i + 1][r]\n                        )\n                    elif oper[i] == '|':\n                        t[l][r] += (\n                            (t[l][i] + f[l][i]) *\n                            (t[i + 1][r] + f[i + 1][r]) -\n                            f[l][i] * f[i + 1][r]\n                        )\n                        f[l][r] += f[l][i] * f[i + 1][r]\n                    elif oper[i] == '^':\n                        t[l][r] += t[l][i] * f[i + 1][r] + f[l][i] * t[i + 1][r]\n                        f[l][r] += t[l][i] * t[i + 1][r] + f[l][i] * f[i + 1][r]\n\n        return t[0][n - 1]\n"
  },
  {
    "path": "lintcode/729_last_digit_by_factorial_divide.py",
    "content": "class Solution:\n    def computeLastDigit(self, a, b):\n        \"\"\"\n        :type a: int\n        :type b: int\n        :rtype: int\n        \"\"\"\n        if not a or not b:\n            return 0\n        if a == b:\n            return 1\n\n        ans = 1\n\n        for num in range(a + 1, b + 1):\n            if ans == 0:\n                return 0\n\n            ans *= num % 10\n            ans %= 10\n\n        return ans\n"
  },
  {
    "path": "lintcode/745_palindromic_ranges.py",
    "content": "class Solution:\n    def PalindromicRanges(self, left, right):\n        \"\"\"\n        :type left: int\n        :type right: int\n        :rtype: int\n        \"\"\"\n        if left > right:\n            return 0\n        if left == right:\n            return 1\n\n        dp = [0] * (right - left + 2)  # n + 1, n = right - left + 1\n        # dp[0] = 0\n\n        for num in range(left, right + 1):\n            if self.is_palindrome(num):\n                dp[num - left + 1] = dp[num - left] + 1\n            else:\n                dp[num - left + 1] = dp[num - left]\n\n        ans = 0\n\n        for i in range(1, right - left + 2):\n            for j in range(i):\n                if ((dp[i] - dp[j]) & 1 == 0):\n                    ans += 1\n\n        return ans\n\n    def is_palindrome(self, num):\n        if num // 10 == 0:\n            return True\n\n        s = str(num)\n        left, right = 0, len(s) - 1\n\n        while left < right:\n            if s[left] != s[right]:\n                return False\n\n            left += 1\n            right -= 1\n\n        return True\n"
  },
  {
    "path": "lintcode/74_first_bad_version.py",
    "content": "\"\"\"\nMain Concept\n    ver. | 1 2 3 4 5\n    good | T T F F F\n\nclass SVNRepo:\n    @classmethod\n    def isBadVersion(cls, id)\n        # Run unit tests to check whether verison `id` is a bad version\n        # return true if unit tests passed else false.\nYou can use SVNRepo.isBadVersion(10) to check whether version 10 is a\nbad version.\n\"\"\"\n\n\nclass Solution:\n    def findFirstBadVersion(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if not n:\n            return 0\n\n        left, right = 1, n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if isBadVersion(mid):\n                right = mid\n            else:\n                left = mid\n\n        return left if isBadVersion(left) else right\n"
  },
  {
    "path": "lintcode/752_rogue_knight_sven.py",
    "content": "class Solution:\n    def getNumberOfWays(self, n, m, limit, cost):\n        \"\"\"\n        :type n: int\n        :type m: int\n        :type limit: int\n        :type cost: List[int]\n        :rtype: int\n        \"\"\"\n\n        \"\"\"\n        `dp[i][j]` means the ways to reach planet `i` and still keep `j` coins\n        \"\"\"\n        dp = [[0] * (m + 1) for _ in range(n + 1)]\n        dp[0][m] = 1\n\n        for i in range(1, n + 1):\n            for j in range(m + 1):\n                for k in range(max(0, i - limit), i):\n                    if j + cost[i] > m:\n                        continue\n                    dp[i][j] += dp[k][j + cost[i]]\n\n        return sum(dp[n])\n"
  },
  {
    "path": "lintcode/75_find_peak_element.py",
    "content": "class Solution:\n    def findPeak(self, nums):\n        \"\"\"\n        :type nums: list\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return -1\n\n        left, right = 0, len(nums) - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n\n            if nums[mid] < nums[mid + 1]:\n                left = mid\n            else:\n                right = mid\n\n        return right if nums[left] < nums[right] else left\n"
  },
  {
    "path": "lintcode/76_longest_increasing_subsequence.py",
    "content": "\"\"\"\nBinary Searching\n\"\"\"\nclass Solution:\n    def longestIncreasingSubsequence(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n\n        the iteration of B:\n        [-inf, 0, inf, inf, inf, inf, inf, inf, inf]\n        [-inf, 0, 8, inf, inf, inf, inf, inf, inf]\n        [-inf, 0, 4, inf, inf, inf, inf, inf, inf]\n        [-inf, 0, 4, 12, inf, inf, inf, inf, inf]\n        [-inf, 0, 2, 12, inf, inf, inf, inf, inf]\n        [-inf, 0, 2, 10, inf, inf, inf, inf, inf]\n        [-inf, 0, 2, 6, inf, inf, inf, inf, inf]\n        [-inf, 0, 2, 6, 14, inf, inf, inf, inf]\n\n        lis_size = 4\n        \"\"\"\n        if not A:\n            return 0\n\n        INFINITY = float('inf')\n        n = len(A)\n        P = [-INFINITY] + [INFINITY] * n\n\n        for i in range(n):\n            j = self.binary_search(P, A[i])\n            P[j] = A[i]\n\n        for i in range(n, -1, -1):\n            if P[i] < INFINITY:\n                return i\n\n        return 0\n\n    def binary_search(self, P, a):\n        left, right = 0, len(P) - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if P[mid] < a:\n                left = mid\n            else:\n                right = mid\n\n        return right\n\n\n\"\"\"\nDP + Print Paths\n\"\"\"\nclass Solution:\n    def longestIncreasingSubsequence(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        lis_size = 0\n        if not A:\n            return lis_size\n\n        n = len(A)\n\n        \"\"\"\n        `dp[i]` means the maximum size of LIS end at `i`\n        note that there is size, so init with `1`\n        \"\"\"\n        dp = [1] * n\n        # pi = [0] * n\n        # end_at = -1\n\n        for i in range(n):\n            for j in range(i):\n                \"\"\"\n                `dp[j]` the existing subseq end at `j`\n                `+ 1` means included `A[i]`\n                \"\"\"\n                if A[j] < A[i] and dp[j] + 1 > dp[i]:\n                    dp[i] = dp[j] + 1\n                    # pi[i] = j\n\n                if dp[i] > lis_size:\n                    lis_size = dp[i]\n                    # end_at = i\n\n        # paths = [0] * lis_size\n        # for i in range(lis_size - 1, -1, -1):\n        #     paths[i] = A[end_at]\n        #     end_at = pi[end_at]\n        # print(paths)\n\n        return lis_size\n"
  },
  {
    "path": "lintcode/772_group_anagrams.py",
    "content": "class Solution:\n    \"\"\"\n    @param s: the given array of strings\n    @return: The anagrams which have been divided into groups\n    \"\"\"\n    def groupAnagrams(self, s):\n        if not s:\n            return []\n\n        group = {}\n\n        for w in s:\n            key = ''.join(sorted(w))\n            if key not in group:\n                group[key] = []\n            group[key].append(w)\n\n        return sorted([sorted(g) for g in group.values()])\n"
  },
  {
    "path": "lintcode/775_palindrome_pairs.py",
    "content": "\"\"\"\nREF: https://leetcode.com/problems/palindrome-pairs/discuss/79199/150-ms-45-lines-JAVA-solution\n\nMain Concept:\n\n1. The <= in for (int j=0; j<=words[i].length(); j++) is aimed to handle empty string in the input. Consider the test case of [“a”, “”];\n2. Since we now use <= in for (int j=0; j<=words[i].length(); j++) instead of <. There may be duplicates in the output (consider test case [“abcd”, “dcba”]). Therefore I put a str2.length()!=0 to avoid duplicates.\n\"\"\"\nclass Solution:\n    def palindromePairs(self, words):\n        \"\"\"\n        :type words: list[str]\n        :rtype: list[list[int]]\n        \"\"\"\n        ans = []\n\n        if not words:\n            return ans\n\n        n = len(words)\n        w2i = {}\n\n        for i in range(n):\n            w2i[words[i]] = i\n\n        for i in range(n):\n            for j in range(len(words[i]) + 1):\n                s = words[i][:j]\n                t = words[i][j:]\n                _s = ''.join(reversed(s))\n                _t = ''.join(reversed(t))\n\n                if (self.is_palindrome(s) and\n                    _t in w2i and\n                    w2i[_t] != i\n                ):\n                    ans.append([w2i[_t], i])\n\n                if (self.is_palindrome(t) and\n                    len(t) != 0 and  # since len(word) + 1, may empty here\n                    _s in w2i and\n                    w2i[_s] != i\n                ):\n                    ans.append([i, w2i[_s]])\n\n        return ans\n\n    def is_palindrome(self, word):\n        n = len(word)\n        left, right = 0, n - 1\n\n        while left < right:\n            if word[left] != word[right]:\n                return False\n\n            left += 1\n            right -= 1\n\n        return True\n\n\n\"\"\"\nTLE: Brute Force\n\"\"\"\nclass Solution:\n    def palindromePairs(self, words):\n        \"\"\"\n        :type words: list[str]\n        :rtype: list[list[int]]\n        \"\"\"\n        ans = []\n\n        if not words:\n            return ans\n\n        n = len(words)\n\n        for i in range(n):\n            for j in range(i):\n                if self.is_palindrome(words, i, j):\n                    ans.append([i, j])\n\n                if self.is_palindrome(words, j, i):\n                    ans.append([j, i])\n\n        return ans\n\n    def is_palindrome(self, words, i, j):\n        s, t = words[i], words[j]\n        a, b = len(s), len(t)\n        n = a + b\n        left, right = 0, n - 1\n\n        while left < right:\n            if left >= a and t[left - a] != t[right - a]:\n                return False\n            elif right < a and s[left] != s[right]:\n                return False\n            elif left < a and right >= a and s[left] != t[right - a]:\n                return False\n\n            left += 1\n            right -= 1\n\n        return True\n\n\n\"\"\"\nTLE: Brute Force\n\"\"\"\nclass Solution:\n    def palindromePairs(self, words):\n        \"\"\"\n        :type words: list[str]\n        :rtype: list[list[int]]\n        \"\"\"\n        ans = []\n\n        if not words:\n            return ans\n\n        n = len(words)\n\n        for i in range(n):\n            for j in range(n):\n                if i == j:\n                    continue\n\n                if self.is_palindrome(words[i] + words[j]):\n                    ans.append([i, j])\n\n        return ans\n\n    def is_palindrome(self, s):\n        n = len(s)\n        left, right = 0, n - 1\n\n        while left < right:\n            if s[left] != s[right]:\n                return False\n\n            left += 1\n            right -= 1\n\n        return True\n"
  },
  {
    "path": "lintcode/776_strobogrammatic_number_ii.py",
    "content": "class Solution:\n    def findStrobogrammatic(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: list[str]\n        \"\"\"\n        ans = ['']\n\n        if not n:\n            return ans\n\n        if n & 1:\n            ans = ['0', '1', '8']\n            n -= 1\n\n        while n:\n            queue = []\n\n            for s in ans:\n                if n != 2:\n                    queue.append('0' + s + '0')\n\n                queue.append('1' + s + '1')\n                queue.append('8' + s + '8')\n                queue.append('6' + s + '9')\n                queue.append('9' + s + '6')\n\n            ans = queue\n            n -= 2\n\n        return ans\n"
  },
  {
    "path": "lintcode/77_longest_common_subsequence.py",
    "content": "class Solution:\n    \"\"\"\n    @param: A: A string\n    @param: B: A string\n    @return: The length of longest common subsequence of A and B\n    \"\"\"\n    def longestCommonSubsequence(self, A, B):\n        \"\"\"\n        remove the single line comment to print paths\n        \"\"\"\n        if not A or not B:\n            return 0\n\n        m, n = len(A), len(B)\n\n        \"\"\"\n        `dp[i][j]` means the size of LCS, consisting of\n        the substr end at `A[i - 1]` and the substr end at `B[j - 1]`\n\n        dp[0][j] = 0\n        dp[i][0] = 0\n        \"\"\"\n        dp = [[0] * (n + 1) for _ in range(2)]\n        # pi = [[0] * (n + 1) for _ in range(m + 1)]\n\n        prev = curr = 0\n        for i in range(1, m + 1):\n            prev = curr\n            curr = 1 - curr\n            for j in range(1, n + 1):\n                \"\"\"\n                case 1: `A[i]` is not one of pairs\n                case 2: `B[j]` is not one of pairs\n                case 3: `A[i]` and `B[j]` is just a pair\n                \"\"\"\n                dp[curr][j] = max(dp[prev][j], dp[curr][j - 1])\n\n                # if dp[curr][j] == dp[prev][j]:\n                #     pi[i][j] = 1\n                # else:\n                #     pi[i][j] = 2\n\n                if A[i - 1] == B[j - 1]:\n                    dp[curr][j] = max(dp[curr][j], dp[prev][j - 1] + 1)\n\n                    # if dp[curr][j] == dp[prev][j - 1] + 1:\n                    #     pi[i][j] = 3\n\n        # path = [None] * dp[curr][n]\n        # i, j, k = m, n, dp[curr][n] - 1\n\n        # while i > 0 and j > 0:\n        #     if pi[i][j] == 1:\n        #         i -= 1\n        #     elif pi[i][j] == 2:\n        #         j -= 1\n        #     else:\n        #         path[k] = A[i - 1]  # or B[j - 1], its same\n        #         k -= 1\n        #         i -= 1\n        #         j -= 1\n\n        # print(path)\n\n        return dp[curr][n]\n"
  },
  {
    "path": "lintcode/784_the_longest_common_prefix_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param D: the n strings\n    @param target: the target string\n    @return: The ans\n    \"\"\"\n    def theLongestCommonPrefix(self, D, target):\n        ans = 0\n\n        for word in D:\n            i = 0\n            for c in word:\n                if c != target[i]:\n                    break\n                i += 1\n            if i > ans:\n                ans = i\n\n        return ans\n"
  },
  {
    "path": "lintcode/790_parser.py",
    "content": "class Solution:\n    \"\"\"\n    @param S: Generating set of rules.\n    @param s: Start symbol.\n    @param e: Symbol string.\n    @return: Return true if the symbol string can be generated, otherwise return false.\n    \"\"\"\n    def canBeGenerated(self, S, start, end):\n        if not start:\n            start = ''\n\n        N = {}\n\n        for s in S:\n            cur, nxt = s.split(' -> ')\n            if cur not in N:\n                N[cur] = set()\n            N[cur].add(nxt)\n\n        return self.dfs(N, end, start)\n\n    def dfs(self, N, end, s):\n        if len(s) > len(end):\n            return False\n        if s == end:\n            return True\n\n        for i in range(len(s)):\n            if (not ord('A') <= ord(s[i]) <= ord('Z') or\n                s[i] not in N):\n                continue\n\n            for _s in N[s[i]]:\n                res = self.dfs(N, end, s[:i] + _s + s[i + 1:])\n                if res:\n                    return True\n\n        return False\n"
  },
  {
    "path": "lintcode/791_merge_number.py",
    "content": "from heapq import heappush, heappop\n\n\nclass Solution:\n    \"\"\"\n    @param A: the numbers\n    @return: the minimum cost\n    \"\"\"\n    def mergeNumber(self, A):\n        ans = 0\n        if not A:\n            return ans\n\n        heap = []\n\n        for a in A:\n            heappush(heap, a)\n\n        while len(heap) > 1:\n            _sum = heappop(heap) + heappop(heap)\n            ans += _sum\n            heappush(heap, _sum)\n\n        return ans\n"
  },
  {
    "path": "lintcode/792_kth_prime_number.py",
    "content": "class Solution:\n    \"\"\"\n    @param n: the number\n    @return: the rank of the number\n    \"\"\"\n    def kthPrime(self, n):\n        if not n or n < 3:\n            return 1\n\n        is_prime = [True] * n\n        is_prime[0] = is_prime[1] = False\n\n        for i in range(2, int(n ** 0.5) + 1):\n            if not is_prime[i]:\n                continue\n            for j in range(i * i, n, i):\n                is_prime[j] = False\n\n        return sum(is_prime) + 1\n"
  },
  {
    "path": "lintcode/793_intersection_of_arrays.py",
    "content": "class Solution:\n    \"\"\"\n    @param A: the arrays\n    @return: the number of the intersection of the arrays\n    \"\"\"\n    def intersectionOfArrays(self, A):\n        ans = 0\n        if not A:\n            return ans\n\n        n = len(A)\n        C = {}\n\n        for i in range(n):\n            if not A[i]:\n                return ans\n\n            for a in A[i]:\n                if a not in C:\n                    C[a] = set()\n                C[a].add(i)\n\n        for a, S in C.items():\n            if len(S) == n:\n                ans += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/7_binary_tree_serialization.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    EMPTY = '#'\n\n    def serialize(self, root):\n        \"\"\"Encodes a tree to a single string.\n        :type root: TreeNode\n        :rtype: str\n        \"\"\"\n        TEMPLATE = '{{{}}}'  # {{, }} is to escape brackets\n        if not root:\n            return TEMPLATE.format('')\n\n        vals = []\n        queue = [root]\n\n        for node in queue:\n            if not node:\n                vals.append(self.EMPTY)\n                continue\n\n            vals.append(str(node.val))\n            queue.append(node.left)\n            queue.append(node.right)\n\n        while vals[-1] == self.EMPTY:\n            vals.pop()\n\n        return TEMPLATE.format(','.join(vals))\n\n    def deserialize(self, data):\n        \"\"\"Decodes your encoded data to tree.\n        :type data: str\n        :rtype: TreeNode\n        \"\"\"\n        if (not data or\n            data[0] != '{' or\n            data[-1] != '}' or\n            len(data) < 3 or\n            data[1] == '#'\n        ):\n            return\n\n        vals = data[1:-1].split(',')\n        n = len(vals)\n        i = 0\n\n        root = TreeNode(int(vals[i]))\n        queue = [root]\n\n        for node in queue:\n            for branch in ('left', 'right'):\n                i += 1\n\n                if i >= n:\n                    break\n                if vals[i] == self.EMPTY:\n                    continue\n\n                setattr(node, branch, TreeNode(int(vals[i])))\n                queue.append(getattr(node, branch))\n\n        return root\n"
  },
  {
    "path": "lintcode/813_find_anagram_mappings.py",
    "content": "\"\"\"\nFind last pos\n\"\"\"\nclass Solution:\n    def anagramMappings(self, a, b):\n        \"\"\"\n        :type a: list[int]\n        :type b: list[int]\n        :rtype: list[int]\n        \"\"\"\n        if not a or not b or len(a) != len(b):\n            return []\n\n        n = len(a)\n        ans = [-1] * n\n        b2i = {}\n\n        for i in range(n):\n            b2i[b[i]] = i\n\n        for i in range(n):\n            if a[i] not in b2i:\n                return []\n\n            ans[i] = b2i[a[i]]\n\n        return ans\n\n\n\"\"\"\nStrict\n\"\"\"\nclass Solution:\n    def anagramMappings(self, a, b):\n        \"\"\"\n        :type a: list[int]\n        :type b: list[int]\n        :rtype: list[int]\n        \"\"\"\n        if not a or not b or len(a) != len(b):\n            return []\n\n        n = len(a)\n        ans = [-1] * n\n        b2i = {}\n\n        for i in range(n):\n            if b[i] not in b2i:\n                b2i[b[i]] = []\n\n            b2i[b[i]].append(i)\n\n        for i in range(n):\n            if not b2i.get(a[i]):\n                # a[i] not in b2i\n                # b2i[a[i]] is empty list\n                return []\n\n            ans[i] = b2i[a[i]].pop()\n\n        return ans\n"
  },
  {
    "path": "lintcode/81_data_stream_median.py",
    "content": "import heapq\n\n\nclass Solution:\n    def medianII(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: list[int]\n        \"\"\"\n        ans = []\n        if not nums:\n            return ans\n\n        minheap = []\n        maxheap = []\n        median = 0\n\n        for num in nums:\n            if num < median:\n                heapq.heappush(maxheap, -num)\n            else:\n                heapq.heappush(minheap, num)\n\n            while len(minheap) > len(maxheap):\n                heapq.heappush(maxheap, -heapq.heappop(minheap))\n\n            while len(maxheap) > len(minheap) + 1:\n                heapq.heappush(minheap, -heapq.heappop(maxheap))\n\n            if maxheap:\n                median = -maxheap[0]\n            else:\n                median = 0\n\n            ans.append(median)\n\n        return ans\n"
  },
  {
    "path": "lintcode/823_input_stream.py",
    "content": "\"\"\"\nMerge Sort\ntime: O(n)\nspace: O(1)\n\"\"\"\nclass Solution:\n    def inputStream(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: str, 'NO' or 'YES'\n        \"\"\"\n        RES = ('NO', 'YES')\n\n        if a == b == '':\n            return RES[1]\n\n        BACK = '<'\n        m, n = len(a), len(b)\n        i, j = m - 1, n - 1\n        acnt = bcnt = 0  # count the backspace in both a and b\n\n        while i >= 0 and j >= 0:\n            while i >= 0 and (a[i] == BACK or acnt):\n                acnt += 1 if a[i] == BACK else -1\n                i -= 1\n            while j >= 0 and (b[j] == BACK or bcnt):\n                bcnt += 1 if b[j] == BACK else -1\n                j -= 1\n\n            if a[i] != b[j]:\n                return RES[0]\n\n            i -= 1\n            j -= 1\n\n        while i >= 0 and (a[i] == BACK or acnt):\n            acnt += 1 if a[i] == BACK else -1\n            i -= 1\n        while j >= 0 and (b[j] == BACK or bcnt):\n            bcnt += 1 if b[j] == BACK else -1\n            j -= 1\n\n        return RES[int(i == j)]\n\n\n\"\"\"\nStack\ntime: O(n)\nspace: O(n)\n\"\"\"\nclass Solution:\n    def inputStream(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: str, 'NO' or 'YES'\n        \"\"\"\n        RES = ('NO', 'YES')\n\n        if a == '' and b == '':\n            return RES[1]\n        if a is None or b is None:\n            return RES[0]\n\n        RM = '<'\n        stack = []\n\n        for c in a:\n            if c != RM:\n                stack.append(c)\n            elif stack:\n                # c == RM\n                stack.pop()\n\n        _stack = []\n\n        for c in b:\n            if c != RM:\n                _stack.append(c)\n            elif _stack:\n                # c == RM\n                _stack.pop()\n\n        return RES[int(stack == _stack)]\n"
  },
  {
    "path": "lintcode/824_single_number_iv.py",
    "content": "class Solution:\n    def getSingleNumber(self, nums):\n        \"\"\"\n        :type nums: list[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return -1\n\n        if len(nums) == 1:\n            return nums[0]\n\n        n = len(nums)\n        left, right = 0, n - 1\n\n        while left + 1 < right:\n            mid = (left + right) // 2\n            if mid > 0 and nums[mid] == nums[mid - 1]:\n                if mid & 1 == 1:\n                    left = mid\n                else:\n                    right = mid\n            else:\n                if mid & 1 == 1:\n                    right = mid\n                else:\n                    left = mid\n\n        for mid in (left, right):\n            if mid > 0 and nums[mid] == nums[mid - 1]:\n                continue\n            if mid + 1 < n and nums[mid] == nums[mid + 1]:\n                continue\n            return nums[mid]\n\n        return -1\n"
  },
  {
    "path": "lintcode/826_computer_maintenance.py",
    "content": "class Solution:\n    \"\"\"\n    @param m: the rows of matrix\n    @param n: the cols of matrix\n    @param P: the bad computers\n    @return: The answer\n    \"\"\"\n    def maintenance(self, m, n, P):\n        if not m or not n or not P:\n            return 0\n\n        dp = [[0, 0] for _ in range(m)]\n        G = [[0] * n for _ in range(m)]\n\n        for p in P:\n            G[p.x][p.y] = 1\n\n        for i in range(m):\n            left = right = -1\n\n            for j in range(n):\n                if G[i][j] == 0:\n                    continue\n                left = max(left, n - 1 - j)\n                right = max(right, j)\n\n            if i == 0:\n                if right == -1:\n                    dp[i][0] = 0\n                    dp[i][1] = n - 1\n                else:\n                    dp[i][0] = 2 * right\n                    dp[i][1] = n - 1\n            else:\n                if right == -1:\n                    dp[i][0] = dp[i - 1][0] + 1\n                    dp[i][1] = dp[i - 1][1] + 1\n                else:\n                    dp[i][0] = 1 + min(\n                        dp[i - 1][0] + 2 * right,\n                        dp[i - 1][1] + n - 1\n                    )\n                    dp[i][1] = 1 + min(\n                        dp[i - 1][1] + 2 * left,\n                        dp[i - 1][0] + n - 1\n                    )\n\n        return min(dp[m - 1][0], dp[m - 1][1])\n"
  },
  {
    "path": "lintcode/830_string_sort.py",
    "content": "class Solution:\n    \"\"\"\n    @param s: the string that needs to be sorted\n    @return: sorted string\n    \"\"\"\n    def stringSort(self, s):\n        if not s:\n            return ''\n\n        return ''.join(sorted(s, key=lambda c: (-s.count(c), c)))\n"
  },
  {
    "path": "lintcode/831_3sum_ii.py",
    "content": "class Solution:\n    \"\"\"\n    @param n: an integer\n    @return: the number of solutions\n    \"\"\"\n    def threeSum2(self, n):\n        ans = 0\n        nums = []\n\n        for a in range(n + 1):\n            if a * a > n:\n                break\n            nums.append(a * a)\n            nums.append(a * a)\n            nums.append(a * a)\n\n        m = len(nums)\n\n        for a in range(m - 2):\n            if a > 0 and nums[a] == nums[a - 1]:\n                continue\n\n            b = a + 1\n            c = m - 1\n            while b < c:\n                _sum = nums[a] + nums[b] + nums[c]\n                if _sum < n:\n                    b += 1\n                elif _sum > n:\n                    c -= 1\n                else:\n                    ans += 1\n                    b += 1\n                    c -= 1\n                    while b < c and nums[b] == nums[b - 1]:\n                        b += 1\n                    while b < c and nums[c] == nums[c + 1]:\n                        c -= 1\n\n        return ans\n\n\nclass Solution:\n    \"\"\"\n    @param n: an integer\n    @return: the number of solutions\n    \"\"\"\n    def threeSum2(self, n):\n        ans = 0\n        m = int(n ** 0.5)\n\n        for a in range(m + 1):\n            target = n - a * a\n            b, c = a, m\n            while b <= c:\n                _sum = b * b + c * c\n                if _sum < target:\n                    b += 1\n                elif _sum > target:\n                    c -= 1\n                else:\n                    ans += 1\n                    b += 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/832_count_negative_number.py",
    "content": "class Solution:\n    \"\"\"\n    @param g: the sorted matrix\n    @return: the number of Negative Number\n    \"\"\"\n    def countNumber(self, g):\n        ans = 0\n        if not g or not g[0]:\n            return ans\n\n        m, n = len(g), len(g[0])\n\n        for i in range(m):\n            left, right = 0, n - 1\n\n            while left + 1 < right:\n                mid = (left + right) // 2\n                if g[i][mid] < 0:\n                    left = mid\n                else:\n                    right = mid\n\n            if g[i][left] >= 0:\n                continue\n\n            ans += left + 1 if g[i][right] >= 0 else right + 1\n\n        return ans\n"
  },
  {
    "path": "lintcode/833_process_sequence.py",
    "content": "class Solution:\n    \"\"\"\n    @param logs: Sequence of processes\n    @param queries: Sequence of queries\n    @return: Return the number of processes\n    \"\"\"\n    def numberOfProcesses(self, logs, queries):\n        time = []\n\n        # 0: end, 1: start, 2: in progress\n        for log in logs:\n            time.append((log.start, 1))\n            time.append((log.end + 1, 0))\n\n        for t in queries:\n            time.append((t, 2))\n\n        time.sort()\n\n        cnt = 0\n        time2cnt = {}\n\n        for t, status in time:\n            if status == 0:\n                cnt -= 1\n            elif status == 1:\n                cnt += 1\n\n            time2cnt[t] = cnt\n\n        return [time2cnt[t] for t in queries]\n"
  },
  {
    "path": "lintcode/85_insert_node_in_a_binary_search_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\n# recursion\nclass Solution:\n    \"\"\"\n    @param: root: The root of the binary search tree.\n    @param: node: insert this node into the binary search tree\n    @return: The root of the new binary search tree.\n    \"\"\"\n    def insertNode(self, root, node):\n        if not root:\n            return node\n\n        if node.val < root.val:\n            root.left = self.insertNode(root.left, node)\n        else:\n            root.right = self.insertNode(root.right, node)\n\n        return root\n\n\n# iteration\nclass Solution:\n    \"\"\"\n    @param: root: The root of the binary search tree.\n    @param: node: insert this node into the binary search tree\n    @return: The root of the new binary search tree.\n    \"\"\"\n    def insertNode(self, root, node):\n        if not root:\n            return node\n\n        curr = root\n        while curr is not node:\n            if node.val < curr.val:\n                if curr.left is None:\n                    curr.left = node\n                curr = curr.left\n            else:\n                if curr.right is None:\n                    curr.right = node\n                curr = curr.right\n\n        return root\n"
  },
  {
    "path": "lintcode/86_binary_search_tree_iterator.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\nExample of iterate a tree:\niterator = BSTIterator(root)\nwhile iterator.hasNext():\n    node = iterator.next()\n    do something for node\n\"\"\"\n\n\nclass BSTIterator:\n    \"\"\"\n    @param: root: The root of binary tree.\n    \"\"\"\n    def __init__(self, root):\n        self.stack = []\n        self.node = root\n\n    \"\"\"\n    @return: True if there has next node, or false\n    \"\"\"\n    def hasNext(self):\n        return self.node or self.stack\n\n    \"\"\"\n    @return: return next node\n    \"\"\"\n    def next(self):\n        node = self.node\n        stack = self.stack\n\n        while node:\n            stack.append(node)\n            node = node.left\n\n        node = stack.pop()\n\n        nxt = node\n\n        self.node = node.right\n\n        return nxt\n"
  },
  {
    "path": "lintcode/87_remove_node_in_binary_search_tree.py",
    "content": "\"\"\"\nMain Concept:\nhttps://discuss.leetcode.com/topic/65792/recursive-easy-to-understand-java-solution\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: The root of the binary search tree.\n    @param: target: Remove the node with given value.\n    @return: The root of the binary search tree after removal.\n    \"\"\"\n    def removeNode(self, root, target):\n        if not root:\n            return root\n\n        if root.val == target:\n            if not root.left:\n                return root.right\n            if not root.right:\n                return root.left\n\n            min_node = self.find_min(root.right)\n            root.val = min_node.val\n            root.right = self.removeNode(root.right, root.val)\n\n            return root\n\n        if target < root.val:\n            root.left = self.removeNode(root.left, target)\n        else:\n            root.right = self.removeNode(root.right, target)\n\n        return root\n\n    def find_min(self, node):\n        if not node:\n            return node\n        while node.left:\n            node = node.left\n        return node\n"
  },
  {
    "path": "lintcode/88_lowest_common_ancestor.py",
    "content": "\"\"\"\nNotice:\nAssume two nodes are exist in tree.\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def lowestCommonAncestor(self, root, a, b):\n        \"\"\"\n        :type root: TreeNode\n        :type a: TreeNode\n        :type b: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root or root is a or root is b:\n            return root\n\n        left = self.lowestCommonAncestor(root.left, a, b)\n        right = self.lowestCommonAncestor(root.right, a, b)\n\n        if left and right:\n            return root\n        if left:\n            return left\n        if right:\n            return right\n"
  },
  {
    "path": "lintcode/89_k_sum.py",
    "content": "class Solution:\n    \"\"\"\n    @param A: An integer array\n    @param K: A positive integer (K <= length(A))\n    @param target: An integer\n    @return: An integer\n    \"\"\"\n    def kSum(self, A, K, target):\n        n = len(A)\n\n        \"\"\"\n        `dp[i][j][k]` means the ways we can take `j` in previous `i` nums and its sum equals `k`\n        \"\"\"\n        dp = [[[0] * (target + 1) for _ in range(K + 1)] for _ in range(n + 1)]\n\n        for i in range(n + 1):\n            dp[i][0][0] = 1\n\n        for i in range(1, n + 1):\n            for j in range(1, min(K, i) + 1):\n                for k in range(1, target + 1):\n                    if k >= A[i - 1]:\n                        dp[i][j][k] += dp[i - 1][j - 1][k - A[i - 1]]\n\n                    dp[i][j][k] += dp[i - 1][j][k]\n\n        return dp[n][K][target]\n"
  },
  {
    "path": "lintcode/8_rotate_string.py",
    "content": "class Solution:\n    \"\"\"\n    @param: S: An array of char\n    @param: x: An integer\n    @return: nothing\n    \"\"\"\n    def rotateString(self, S, x):\n        if not S or not x:\n            return S\n\n        n = len(S)\n        x %= n\n        self.reverse(S, 0, n - x - 1)\n        self.reverse(S, n - x, n - 1)\n        self.reverse(S, 0, n - 1)\n\n    def reverse(self, S, start, end):\n        while start < end:\n            S[start], S[end] = S[end], S[start]\n            start += 1\n            end -= 1\n"
  },
  {
    "path": "lintcode/900_closest_binary_search_tree_value.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def closestValue(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: float\n        :rtype: int\n        \"\"\"\n        if not root:\n            return float('-inf')\n\n        if root.left and target < root.val:\n            left = self.closestValue(root.left, target)\n\n            if abs(left - target) < abs(root.val - target):\n                return left\n\n        if root.right and target > root.val:\n            right = self.closestValue(root.right, target)\n\n            if abs(right - target) < abs(root.val - target):\n                return right\n\n        return root.val\n"
  },
  {
    "path": "lintcode/901_closest_binary_search_tree_value_ii.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def closestKValues(self, root, target, k):\n        \"\"\"\n        :type root: TreeNode\n        :type target: float\n        :type k: int\n        \"\"\"\n        ans = []\n\n        if not root:\n            return ans\n\n        vals = []\n        self.inorder_traverse(root, vals)\n\n        n = len(vals)\n        i = 0\n\n        while i < n and vals[i] < target:\n            i += 1\n\n        i, j = i - 1, i\n\n        while k and i >= 0 and j < n:\n            if target - vals[i] < vals[j] - target:\n                ans.append(vals[i])\n                i -= 1\n            else:\n                ans.append(vals[j])\n                j += 1\n            k -= 1\n\n        while k and i >= 0:\n            ans.append(vals[i])\n            i -= 1\n            k -= 1\n\n        while k and j < n:\n            ans.append(vals[j])\n            j += 1\n            k -= 1\n\n        return ans\n\n    def inorder_traverse(self, root, vals):\n        if not root:\n            return\n\n        self.inorder_traverse(root.left, vals)\n        vals.append(root.val)\n        self.inorder_traverse(root.right, vals)\n"
  },
  {
    "path": "lintcode/919_meeting_rooms_ii.py",
    "content": "\"\"\"\nDefinition of Interval.\nclass Interval(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n\"\"\"\n\n\nclass Solution:\n    def minMeetingRooms(self, intervals):\n        \"\"\"\n        :type intervals: list[Interval]\n        :rtype: int\n        \"\"\"\n        ans = 0\n\n        if not intervals:\n            return ans\n\n        time = []\n\n        for x in intervals:\n            time.append((x.start, True))\n            time.append((x.end, False))\n\n        time.sort()\n\n        cnt = 0\n\n        for t, is_start in time:\n            if is_start:\n                cnt += 1\n            else:\n                cnt -= 1\n\n            if cnt > ans:\n                ans = cnt\n\n        return ans\n"
  },
  {
    "path": "lintcode/920_meeting_rooms.py",
    "content": "\"\"\"\nDefinition of Interval.\nclass Interval:\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n\"\"\"\n\n\n\"\"\"\nSweep Line\ntime: O(n)\nspace: O(n)\n\"\"\"\nclass Solution:\n    def canAttendMeetings(self, intervals):\n        \"\"\"\n        :type intervals: list[Interval]\n        :rtype: bool\n        \"\"\"\n        timeline = []\n\n        for interval in intervals:\n            timeline.append((interval.start, True))\n            timeline.append((interval.end, False))\n\n        timeline.sort()\n\n        cnt = 0\n\n        for time, is_start in timeline:\n            if is_start:\n                cnt += 1\n            else:\n                cnt -= 1\n\n            if cnt > 1:\n                return False\n\n        return True\n\n\n\"\"\"\nSorting\ntime: O(nlogn)\nspace: O(1)\n\"\"\"\nclass Solution:\n    def canAttendMeetings(self, intervals):\n        \"\"\"\n        :type intervals: list[Interval]\n        :rtype: bool\n        \"\"\"\n        intervals.sort(key=lambda x: (x.start, x.end))\n\n        for i in range(1, len(intervals)):\n            if intervals[i].start < intervals[i - 1].end:\n                return False\n\n        return True\n"
  },
  {
    "path": "lintcode/92_backpack.py",
    "content": "class Solution:\n    # @param m: An integer m denotes the size of a backpack\n    # @param A: Given n items with size A[i]\n    # @return: The maximum size\n    def backPack(self, m, A):\n        if not A:\n            return 0\n\n        n = len(A)\n        dp = [[False] * (m + 1) for _ in range(n + 1)]\n        dp[0][0] = True\n\n        for i in range(1, n + 1):\n            for j in range(m + 1):\n                dp[i][j] = dp[i - 1][j]\n                if (j >= A[i - 1]\n                    and dp[i - 1][j - A[i - 1]]):\n                    dp[i][j] = True\n\n        for j in range(m, -1, -1):\n            if dp[n][j]:\n                return j\n\n        return 0\n"
  },
  {
    "path": "lintcode/93_balanced_binary_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: root: The root of binary tree.\n    @return: True if this Binary tree is Balanced, or false.\n    \"\"\"\n    def isBalanced(self, root):\n        return self._divide_conquer(root)[0]\n\n    def _divide_conquer(self, node):\n        if not node:\n            return True, 0\n\n        is_balanced_left, maxdepth_left = self._divide_conquer(node.left)\n        if not is_balanced_left:\n            return False, 0\n\n        is_balanced_right, maxdepth_right = self._divide_conquer(node.right)\n        if not is_balanced_right:\n            return False, 0\n\n        return abs(maxdepth_left - maxdepth_right) <= 1, \\\n            max(maxdepth_left, maxdepth_right) + 1\n"
  },
  {
    "path": "lintcode/95_validate_binary_search_tree.py",
    "content": "\"\"\"\nMain Concept:\nsince the fact,\nif we said a tree is NOT a binary search tree,\nand then the values we got by inorder traversal\nis must be a non-descending sequence, that is, A[i+1] >= A[i].\n\n\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    def isValidBST(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        stack = []\n        node = root\n        pre = None\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n\n            if pre and node.val <= pre.val:\n                return False\n\n            pre = node\n\n            node = node.right\n\n        return True\n\n\nclass Solution:\n    ans = True\n    pre = None\n\n    def isValidBST(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        if not root:\n            return self.ans\n\n        self.isValidBST(root.left)\n\n        if self.pre and root.val <= self.pre.val:\n            self.ans = False\n            return self.ans\n\n        self.pre = root\n\n        self.isValidBST(root.right)\n\n        return self.ans\n"
  },
  {
    "path": "lintcode/96_partition_list.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: The first node of linked list\n    @param: x: An integer\n    @return: A ListNode\n    \"\"\"\n    def partition(self, head, x):\n        if not head:\n            return\n\n        left_dummy = left_tail = ListNode(-1)\n        right_dummy = right_tail = ListNode(-1)\n\n        while head:\n            node = ListNode(head.val)\n            if head.val < x:\n                left_tail.next = node\n                left_tail = node\n            else:\n                right_tail.next = node\n                right_tail = node\n            head = head.next\n\n        left_tail.next = right_dummy.next\n        return left_dummy.next\n"
  },
  {
    "path": "lintcode/97_maximum_depth_of_binary_tree.py",
    "content": "\"\"\"\nDefinition of TreeNode:\nclass TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left, self.right = None, None\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param root: The root of binary tree.\n    @return: An integer\n    \"\"\"\n    def maxDepth(self, root):\n        if not root:\n            return 0\n\n        return 1 + max(\n            self.maxDepth(root.left),\n            self.maxDepth(root.right)\n        )\n"
  },
  {
    "path": "lintcode/98_sort_list.py",
    "content": "\"\"\"\nDefinition of ListNode\nclass ListNode(object):\n\n    def __init__(self, val, next=None):\n        self.val = val\n        self.next = next\n\"\"\"\n\n\nclass Solution:\n    \"\"\"\n    @param: head: The head of linked list.\n    @return: You should return the head of the sorted linked list, using constant space complexity.\n    \"\"\"\n    def sortList(self, head):\n        return self.merge_sort(head)\n\n    def quick_sort(self, head):\n        if not head or not head.next:\n            return head\n\n        mid = self.find_middle(head)\n\n        left_dummy = left_tail = ListNode(0)\n        mid_dummy = mid_tail = ListNode(0)\n        right_dummy = right_tail = ListNode(0)\n\n        while head:\n            if head.val < mid.val:\n                left_tail.next = head\n                left_tail = head\n            elif head.val > mid.val:\n                right_tail.next = head\n                right_tail = head\n            else:\n                mid_tail.next = head\n                mid_tail = head\n            head = head.next\n\n        left_tail.next = mid_tail.next = right_tail.next = None\n\n        left_dummy.next = self.quick_sort(left_dummy.next)\n        right_dummy.next = self.quick_sort(right_dummy.next)\n\n        dummy = tail = ListNode(0)\n        for node in [left_dummy, mid_dummy, right_dummy]:\n            tail.next = node.next\n            tail = self.get_tail(tail)\n\n        return dummy.next\n\n    def merge_sort(self, head):\n        if not head or not head.next:\n            return head\n\n        left = head\n        mid = self.find_middle(head)\n        right = mid.next\n        mid.next = None\n\n        left = self.merge_sort(left)\n        right = self.merge_sort(right)\n\n        dummy = tail = ListNode(0)\n\n        while left and right:\n            if left.val < right.val:\n                tail.next = left\n                left = left.next\n            else:\n                tail.next = right\n                right = right.next\n            tail = tail.next\n\n        if left:\n            tail.next = left\n        else:\n            tail.next = right\n\n        return dummy.next\n\n    def find_middle(self, head):\n        slow, fast = head, head.next\n\n        while fast and fast.next:\n            slow = slow.next\n            fast = fast.next.next\n\n        return slow\n\n    def get_tail(self, head):\n        if not head:\n            return\n\n        while head.next:\n            head = head.next\n\n        return head\n"
  },
  {
    "path": "lintcode/9_fizz_buzz.py",
    "content": "class Solution:\n    def fizzBuzz(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[str]\n        \"\"\"\n        ans = []\n\n        if not n:\n            return ans\n\n        for i in range(1, n + 1):\n            if i % 3 == 0 and i % 5 == 0:\n                ans.append('FizzBuzz')\n            elif i % 3 == 0:\n                ans.append('Fizz')\n            elif i % 5 == 0:\n                ans.append('Buzz')\n            else:\n                ans.append(str(i))\n\n        return ans\n\n\nclass Solution:\n    def fizzBuzz(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[str]\n        \"\"\"\n        ans = []\n        if not n:\n            return ans\n\n        a = i3 = i5 = 1\n\n        while a <= n:\n            while a <= n and a < i3 * 3 and a < i5 * 5:\n                ans.append(str(a))\n                a += 1\n\n            if a <= n and a == i3 * 3 and a == i5 * 5:\n                ans.append('fizz buzz')\n                a += 1\n                i3 += 1\n                i5 += 1\n                continue\n\n            while a <= n and a == i3 * 3:\n                ans.append('fizz')\n                a += 1\n                i3 += 1\n\n            while a <= n and a == i5 * 5:\n                ans.append('buzz')\n                a += 1\n                i5 += 1\n\n        return ans\n"
  },
  {
    "path": "other/anti_queue_reconstruction_by_height.py",
    "content": "\"\"\"\nThis question is related with `leetcode/406_queue_reconstruction_by_height`\n\"\"\"\n\n\ndef reorder(nums):\n    \"\"\"\n    :type nums: list[int]\n    :rtype: list[int]\n\n    >>> reorder([0, 1, 2, 1, 0])\n    [4, 2, 1, 3, 5]\n    \"\"\"\n    if not nums:\n        return []\n\n    n = len(nums)\n    ans = [0] * n\n    cands = [i for i in range(1, n + 1)]\n\n    for i in range(n - 1, -1, -1):\n        ans[i] = cands.pop(i - nums[i])\n\n    return ans\n"
  },
  {
    "path": "other/binary_tree_maximum_path_product.py",
    "content": "\"\"\"\nTesting:\n\n>>> class TreeNode:\n...     def __init__(self, val):\n...         self.val = val\n...         self.left = self.right = None\n\n>>> trees = []\n>>> tree_infos = [\n...     ((\n...         (-3, None, None),\n...     ), -3),\n...     ((\n...         (3, 4, 5),\n...         (4, None, None),\n...         (5, None, None),\n...     ), 60),\n...     ((\n...         (3, 4, -5),\n...         (4, None, None),\n...         (-5, None, None),\n...     ), 12),\n...     ((\n...         (3, 4, -5),\n...         (4, -6, 7),\n...         (-5, 2, -9),\n...         (-6, None, None),\n...         (7, None, None),\n...         (2, None, None),\n...         (-9, None, None),\n...     ), 3780),\n...     ((\n...         (0, 4, -5),\n...         (4, -6, 7),\n...         (-5, 2, -9),\n...         (-6, None, None),\n...         (7, None, None),\n...         (2, None, None),\n...         (-9, None, None),\n...     ), 90),\n... ]\n\n>>> for info, _ in tree_infos:\n...     nodes = {node[0]: TreeNode(node[0]) for node in info}\n...\n...     for val, left, right in info:\n...         if left:\n...             nodes[val].left = nodes[left]\n...         if right:\n...             nodes[val].right = nodes[right]\n...\n...     trees.append(nodes[info[0][0]])\n\n>>> gotcha = []\n>>> s = Solution()\n>>> for i in range(len(trees)):\n...     res = s.maxPathProd(trees[i])\n...     if res != tree_infos[i][1]: print(res, tree_infos[i])\n...     gotcha.append(res == tree_infos[i][1])\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    def maxPathProd(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n\n        ans, _, _ = self.divide_conquer(root)\n        return ans\n\n    def divide_conquer(self, node):\n        if not node:\n            return float('-inf'), 1, 1\n\n        res_left, max_left, min_left = self.divide_conquer(node.left)\n        res_right, max_right, min_right = self.divide_conquer(node.right)\n\n        a = node.val * max(max_left, max_right)\n        b = node.val * min(min_left, min_right)\n\n        res = max(\n            # ignoring current (0)\n            res_left,\n            res_right,\n            # only current (1)\n            node.val,\n            # half path (2)\n            a, b,\n            # go through current (3)\n            node.val * max_left * max_right,\n            node.val * min_left * min_right,\n        )\n\n        return res, max(a, b), min(a, b)\n"
  },
  {
    "path": "other/candy_crush.py",
    "content": "\"\"\"\nDesign a algorithm to initialize the board of Candy Crush Saga.\nWith M x N board, Q types of candies.\n\nRules:\n1. with randomization\n2. no 3 for run after initialization\n3. must contain at least one valid move at the beginning\n\nThought:\n1. for random candies and no 3 for run at begining\n    - random generate, and re-gen if invalid\n2. prevent dead loop while checking valid\n    - [x] iterate by order\n      => dead loop may occur when visiting the cells arround prefilled\n    - [v] BFS from the prefilled cell to boundary\n3. at least one valid move at the beginning\n    - just define the patterns (3 for run => 12 patterns)\n      prefill to board, and mark as unchangable\n\nREF:\n1. LC 723\n2. http://massivetechinterview.blogspot.com/2015/11/how-to-initialize-board-of-candy-crush.html\n\nTODO:\n1. implement `move` to move candy to D/R/U/L, and\n    - remove the connected candy\n    - the candy will drop if there is empty below\n2. count score\n3. end up game if no more valid move or the game is finished\n\nTesting:\n>>> gotcha = []\n>>> for params in (\n...     (7, 7, 3), (10, 10, 3), (20, 20, 3),\n...     (7, 7, 5), (10, 10, 4), (20, 20, 6),\n... ):\n...     game = CandyCrush(*params)\n...     for _ in range(5):\n...         game.reset_board()\n...         valid = _check_board_valid(game.get_board())\n...         if not valid: print(game._print_board())\n...         gotcha.append(valid)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\nimport random\n\n\ndef _check_board_valid(board):\n    # for testing\n    m, n = len(board), len(board[0])\n\n    for x in range(2, m):\n        for y in range(n):\n            if board[x][y] == board[x - 1][y] == board[x - 2][y]:\n                return False\n\n    for y in range(2, n):\n        for x in range(m):\n            if board[x][y] == board[x][y - 1] == board[x][y - 2]:\n                return False\n\n    return True\n\n\nclass CandyCrush:\n    def __init__(self, m, n, q):\n        \"\"\"\n        :type m: int\n        :type n: int\n        :type q: int\n        \"\"\"\n        self.width = n\n        self.height = m\n        self.__board = None\n        self.__types = q\n        self.__patterns = (   # with rotating, we can find up to 12 patterns\n            (-1, -1, 1,  0),  # /--\n            (-1,  1, 1,  0),  # --\\\n            (-1, -1, 1, -1),  # /-\\\n        )\n        self.reset_board()\n\n    def reset_board(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        m, n = self.height, self.width\n        b = self.__board = [[-1] * n for _ in range(m)]\n\n        x, y = random.randint(1, m - 2), random.randint(1, n - 2)\n        d = random.choice(self.__patterns)  # dx1, dy1, dx2, dy2\n        q = random.randrange(self.__types)\n\n        queue = [(x + d[0], y + d[1]), (x, y), (x + d[2], y + d[3])]\n        visited = set(queue)\n\n        for x, y in queue:\n            b[x][y] = q\n\n        for x, y in queue:\n            for dx, dy in (\n                (0, -1), (0, 1),\n                (-1, 0), (1, 0),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if (_x, _y) in visited:\n                    continue\n\n                visited.add((_x, _y))\n                queue.append((_x, _y))\n\n                while not self._check_cell_valid(_x, _y):\n                    b[_x][_y] = random.randrange(self.__types)\n\n    def get_board(self):\n        \"\"\"\n        :rtype: list[list[int]]\n        \"\"\"\n        return self.__board\n\n    def _check_cell_valid(self, x, y):\n        \"\"\"\n        :type x: int\n        :type y: int\n        :rtype: bool\n        \"\"\"\n        b = self.__board\n        m, n = self.height, self.width\n\n        if b[x][y] == -1:\n            return False\n\n        for x1, y1, x2, y2 in (\n            (x - 2, y, x - 1, y), (x + 1, y, x + 2, y),  # most up, down\n            (x, y - 2, x, y - 1), (x, y + 1, x, y + 2),  # most left, right\n            (x - 1, y, x + 1, y), (x, y - 1, x, y + 1),  # cross middle\n        ):\n            if not (\n                0 <= x1 < m and 0 <= y1 < n and\n                0 <= x2 < m and 0 <= y2 < n\n            ):\n                continue\n\n            if b[x][y] == b[x1][y1] == b[x2][y2]:\n                return False\n\n        return True\n\n    def _print_board(self):\n        # for testing\n        print('\\n'.join(str(r) for r in self.__board))\n"
  },
  {
    "path": "other/card_shuffler.py",
    "content": "\"\"\"\n>>> CASE = (\n...     (['AB', [1, 0]], 2),\n...     (['ABCD', [1, 2, 3, 0]], 4),\n...     (['ABCDE', [4, 3, 2, 0, 1]], 4),\n...     (['ABCDE', [0, 3, 4, 0, 2]], -1),\n... )\n>>> all(card_shuffler(*inpt) == oupt for inpt, oupt in CASE)\nTrue\n\"\"\"\n\n\ndef card_shuffler(cards, shuffles):\n    \"\"\"\n    :type cards: Iterable[str]\n    :type shuffles: list[int]\n    :rtype: int\n    \"\"\"\n    n = len(cards)\n    offsets = [0] * n\n\n    for i in range(n):\n        offsets[i] = get_offset(i, shuffles)\n        if offsets[i] == -1:\n            return -1\n\n    return get_lcm(*offsets)\n\n\ndef get_offset(start, shuffles):\n    visited = set()\n    i = start\n    offset = 0\n\n    while i not in visited:\n        visited.add(i)\n        i = shuffles[i]\n        offset += 1\n\n    return offset if i == start else -1\n\n\ndef get_lcm(*nums):\n    lcm = nums[0]\n\n    for i in range(1, len(nums)):\n        lcm = lcm // get_gcd(lcm, nums[i]) * nums[i]\n\n    return lcm\n\n\ndef get_gcd(a, b):\n    while b:\n        a, b = b, a % b\n\n    return a\n"
  },
  {
    "path": "other/deep_fetch.js",
    "content": "function deepFetch(target, path, defaultValue = undefined) {\n  if (!target || !Array.isArray(path)) {\n    return defaultValue\n  }\n\n  return path.reduce((level, key) => (\n    (level && level[key]) ? level[key] : defaultValue\n  ), target)\n}\n\n\nmodule.exports = deepFetch\n"
  },
  {
    "path": "other/deep_fetch.test.js",
    "content": "const deepFetch = require('./deep_fetch')\n\ntest('It could deeply fetch props from target', () => {\n  const target = {\n    a: 1,\n    b: 2,\n    c: {\n      d: 3,\n      e: {\n        f: 4,\n        g: 5,\n      },\n    },\n  }\n\n  expect(deepFetch(target, ['b'])).toBe(2)\n  expect(deepFetch(target, ['c', 'd'])).toBe(3)\n  expect(deepFetch(target, ['c', 'e', 'f'])).toBe(4)\n  expect(deepFetch(target, ['c', 'e', 'h'])).toBe(undefined)\n  expect(deepFetch(target, ['c', 'e', 'h'], -1)).toBe(-1)\n})\n"
  },
  {
    "path": "other/find_treasure_in_maze.py",
    "content": "\"\"\"\nhttp://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=82\n\n\nDescription:\n一个叫ACM的寻宝者找到了一个藏宝图，它根据藏宝图找到了一个迷宫，\n这是一个很特别的迷宫，迷宫里有N个编过号的门（N<=5)，\n它们分别被编号为A,B,C,D,E.为了找到宝藏，ACM必须打开门，\n但是，开门之前必须在迷宫里找到这个打开这个门所需的所有钥匙（每个门都至少有一把钥匙），\n例如：现在A门有三把钥匙，ACM就必须找全三把钥匙才能打开A门。\n现在请你编写一个程序来告诉ACM，他能不能顺利的得到宝藏。\n\n每组测试数据的第一行包含了两个整数M,N(1<N,M<20)，分别代表了迷宫的行和列。接下来的M每行有N个字符，描述了迷宫的布局。其中每个字符的含义如下：\n.表示可以走的路\nS:表示ACM的出发点\nG:表示宝藏的位置\nX:表示这里有墙，ACM无法进入或者穿过。\nA,B,C,D,E表示这里是门，a,b,c,d,e表示对应大写字母的门上的钥匙。\n注意ACM只能在迷宫里向上下左右四个方向移动。\n\n\nTesting:\n>>> s = Solution()\n>>> gotcha = []\n>>> for _in, _out in (\n...     (['S.X.', 'a.X.', '..XG', '....'], True),\n...     (['S.Xa', '.aXB', 'b.AG'], False),\n...     (['aX.S', 'bXAB', 'cXCD', 'dXGX'], False),\n...     (['SbAdX.', 'a.BD.G', 'cBCdaX'], True),\n...     (['S.Aa.X.', 'a.Xc.C.', 'b.X..DG', '.cB..Xd'], True),\n... ):\n...     res = s.find_treasure_in_maze(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    START = 'S'\n    GOLD = 'G'\n    OBSTACLE = 'X'\n    EMPTY = '.'\n    DOORS = 'ABCDE'\n    KEYS = 'abcde'\n\n    def find_treasure_in_maze(self, maze):\n        \"\"\"\n        :type maze: list[str]\n        :rtype: bool\n        \"\"\"\n        if not maze or not maze[0]:\n            return False\n\n        m, n = len(maze), len(maze[0])\n        k = len(self.DOORS)\n        keys = [0] * k  # all keys count\n        has_gold = False\n\n        queue = []\n        doors = [None] * k  # doors meet when bfs\n        holds = [0] * k  # keys meet when bfs\n        visited = set()  # visited cell when bfs\n\n        for x in range(m):\n            for y in range(n):\n                if maze[x][y] == self.START:\n                    queue.append((x, y))\n                elif maze[x][y] == self.GOLD:\n                    has_gold = True\n                elif maze[x][y] in self.KEYS:\n                    i = ord(maze[x][y]) - ord('a')\n                    keys[i] += 1\n\n        if not has_gold or not queue:\n            return False\n\n        while queue or self.is_possible(maze, keys, holds, doors):\n            if self.bfs(maze, queue, keys, holds, doors, visited):\n                return True\n\n        return False\n\n    def bfs(self, maze, queue, keys, holds, doors, visited):\n        \"\"\"\n        return True if got gold, otherwise False\n\n        :type maze: list[str]\n        :type queue: list[tuple[int]]\n        :type keys: list[int]\n        :type holds: list[int]\n        :type doors: list[tuple[int]]\n        :type visited: set[tuple[int]]\n        :rtype: bool\n        \"\"\"\n        m, n = len(maze), len(maze[0])\n\n        for x, y in queue:\n            for dx, dy in (\n                (0, -1), (0, 1),\n                (-1, 0), (1, 0),\n            ):\n                _x = x + dx\n                _y = y + dy\n\n                if not (0 <= _x < m and 0 <= _y < n):\n                    continue\n                if (_x, _y) in visited or maze[_x][_y] == self.OBSTACLE:\n                    continue\n                if maze[_x][_y] == self.GOLD:\n                    return True\n\n                if maze[_x][_y] in self.DOORS:\n                    i = ord(maze[_x][_y]) - ord('A')\n                    if holds[i] < keys[i]:\n                        doors[i] = (_x, _y)\n                        continue\n                    doors[i] = None\n\n                if maze[_x][_y] in self.KEYS:\n                    i = ord(maze[_x][_y]) - ord('a')\n                    holds[i] += 1\n\n                visited.add((_x, _y))\n                queue.append((_x, _y))\n\n        queue.clear()\n        return False\n\n    def is_possible(self, maze, keys, holds, doors):\n        \"\"\"\n        :type maze: list[str]\n        :type keys: list[int]\n        :type holds: list[int]\n        :type doors: list[tuple[int]]\n        :rtype: bool\n        \"\"\"\n        for door in doors:\n            if not door:\n                continue\n\n            x, y = door\n            i = ord(maze[x][y]) - ord('A')\n            if holds[i] >= keys[i]:\n                return True\n\n        return False\n"
  },
  {
    "path": "other/find_ways_in_board_game.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for _in, _out in (\n...     (0, 1), (1, 1),\n...     (2, 2), (3, 4),\n...     (4, 8), (5, 16),\n...     (6, 32), (7, 63),\n...     (8, 125), (9, 248),\n... ):\n...     res = find_ways_in_board_game(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef find_ways_in_board_game(n):\n    if not n or n < 2:\n        return 1\n\n    dp = [0] * (n + 1)\n    dp[0] = 1\n\n    for i in range(1, min(n + 1, 6)):\n        for j in range(i):\n            dp[i] += dp[j]\n\n    for i in range(6, n + 1):\n        dp[i] = sum((\n            dp[i - 1],\n            dp[i - 2],\n            dp[i - 3],\n            dp[i - 4],\n            dp[i - 5],\n            dp[i - 6],\n        ))\n\n    return dp[n]\n"
  },
  {
    "path": "other/freq_iterator.py",
    "content": "\"\"\"\nTesting:\n\n>>> gotcha = []\n>>> for _in, _out in (\n...     (\n...         ['foo', 'foo', 'bar', 'foo'],\n...         [['foo', 2], ['bar', 1], ['foo', 1]]\n...     ),\n...     (\n...         ['a', 'a', 'a', 'b', 'b', 'c', 'a', 'b', 'b'],\n...         [['a', 3], ['b', 2], ['c', 1], ['a', 1], ['b', 2]]\n...     ),\n...     (\n...         ['a', 'a', 'a', 'b', 'b', 'c', 'a', 'b', 'c'],\n...         [['a', 3], ['b', 2], ['c', 1], ['a', 1], ['b', 1], ['c', 1]]\n...     ),\n...     (\n...         ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'],\n...         [['a', 1], ['b', 1], ['c', 1],\n...          ['d', 1], ['e', 1], ['f', 1],\n...          ['g', 1], ['h', 1], ['i', 1]]\n...     ),\n... ):\n...     origin_iterator = ListIterator(_in)\n...     res = [origin_iterator.next() for _ in range(len(_in))]\n...     if _in != res: print(_in, res)\n...     gotcha.append(_in == res)\n...     gotcha.append(origin_iterator.has_next() is False)\n...     gotcha.append(origin_iterator.next() is None)\n...\n...     res = []\n...     origin_iterator = ListIterator(_in)\n...     freq_iterator = FreqIterator(origin_iterator)\n...     while freq_iterator.has_next():\n...         res.append(freq_iterator.next())\n...\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass FreqIterator:\n    def __init__(self, iterator):\n        if not iterator or not iterator.has_next():\n            return\n\n        self.iterator = iterator\n        self.pre = None\n        self.word = iterator.next()\n\n    def next(self):\n        if not self.has_next():\n            return\n\n        cnt = 1\n        nxt = None\n\n        while self.iterator.has_next():\n            nxt = self.iterator.next()\n            if nxt != self.word:\n                break\n            cnt += 1\n\n        self.pre = self.word\n        self.word = nxt\n        return [self.pre, cnt]\n\n    def has_next(self):\n        return self.pre != self.word and self.word is not None\n\n\nclass ListIterator:\n    def __init__(self, words):\n        self.words = words\n        self.i = 0\n\n    def next(self):\n        if not self.has_next():\n            return\n\n        res = self.words[self.i]\n        self.i += 1\n        return res\n\n    def has_next(self):\n        if self.i < len(self.words):\n            return True\n\n        return False\n"
  },
  {
    "path": "other/gcd_and_lcm.py",
    "content": "def get_gcd(a, b):\n    \"\"\"\n    :type a: int\n    :type b: int\n    :rtype: int\n\n    >>> get_gcd(10, 2)\n    2\n    >>> get_gcd(500, 375)\n    125\n    \"\"\"\n    while b:\n        a, b = b, a % b\n    return a\n\n\ndef get_lcm(a, b):\n    \"\"\"\n    :type a: int\n    :type b: int\n    :rtype: int\n\n    >>> get_lcm(10, 2)\n    10\n    >>> get_lcm(500, 375)\n    1500\n    \"\"\"\n    return (a * b) // get_gcd(a, b)\n"
  },
  {
    "path": "other/get_most_popular_word.py",
    "content": "\"\"\"\nQuestion:\n\nGiven an integer W that represents number of words and unlimited space complexity.\nWrite functions insert(word) and getMostPopularWord()\nsuch that getMostPopularWord() will always return the most popular word in the last W number of words.\nCreate two solutions that will optimize run-time complexity for either function\nwhile sacrificing the run-time for the other function.\n\nexample1:\nlet W = 2\ninsert('A')\ngetMostPopularWord() => 'A'\ninsert('B')\ngetMostPopularWord() => 'B'\n\nexample2:\nlet W = 3\ninsert('A')\ninsert('A')\ngetMostPopularWord() => 'A'\ninsert('B')\ngetMostPopularWord() => 'A'\ninsert('B')\ngetMostPopularWord() => 'B' // since the first inserted 'A' is out of the scope of the last 3 words\n\nfollow-up1: insert => O(1), getMostPopularWord => O(W)\nfollow-up2: insert => O(W), getMostPopularWord => O(1)\nfollow-up3: insert => O(1), getMostPopularWord => O(1)\n  => like LFU\n    - linked list: save words order\n    - 2d linked list: level1 is freqs list, level2 is words list\n  => bucket sort\n\n\nTesting:\n\n>>> gotcha = []\n>>> for (freq, words), expects in (\n...     ((0, 'AB'), ''),\n...     ((0, 'AABB'), ''),\n...     ((1, 'AB'), 'AB'),\n...     ((1, 'AABB'), 'AABB'),\n...     ((2, 'AB'), 'AB'),\n...     ((2, 'AABB'), 'AABB'),\n...     ((4, 'AB'), 'AB'),\n...     ((4, 'AABB'), 'AAAB'),\n...     ((8, 'AB'), 'AB'),\n...     ((8, 'AABB'), 'AAAB'),\n...     ((8, 'ABABCCCBAC'), 'ABABBCCBBC'),\n... ):\n...     s = Solution(freq)\n...     for i in range(len(words)):\n...         gotcha.append(s.insert(words[i]) is None)\n...         res = s.get_most_popular_word()\n...         if freq == 0:\n...             if res != '': print(freq, words, i, '', res)\n...             gotcha.append(res == '')\n...         else:\n...             if res != expects[i]: print(freq, words, i, expects[i], res)\n...             gotcha.append(res == expects[i])\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Solution:\n    def __init__(self, W):\n        self.cap = W\n\n        self.size = 0\n        self.words = (WordNode(''), WordNode(''))  # D, d for words list\n        self.words[0].nxt = self.words[1]\n        self.words[1].pre = self.words[0]\n\n        self.nodes = {}\n        self.freqs = (FreqNode(0), FreqNode(0))  # D, d for freqs list\n        self.freqs[0].nxt = self.freqs[1]\n        self.freqs[1].pre = self.freqs[0]\n\n    def insert(self, word):\n        if not word or self.cap <= 0:\n            return\n\n        # needs to evict first,\n        # to ensure the coming word will be added at the tail\n        while self.size >= self.cap:\n            self.size -= 1\n            self._evict_word()\n\n        self.size += 1\n        self._add_word(word)\n\n    def get_most_popular_word(self):\n        return self.freqs[1].pre.words[1].pre.word\n\n    def _add_word(self, word):\n        # update self.words\n        node = WordNode(word)\n        node.link(self.words[1].pre, self.words[1])\n\n        # update self.freqs\n        node = from_freq = to_freq = None\n\n        if self.nodes.get(word):\n            node = self.nodes[word]\n            from_freq = node.freq_node\n            node.unlink()\n        else:\n            node = WordNode(word)\n            from_freq = self.freqs[0]\n            self.nodes[word] = node\n\n        if from_freq.nxt.freq == from_freq.freq + 1:\n            to_freq = from_freq.nxt\n        else:\n            to_freq = FreqNode(from_freq.freq + 1)\n            from_freq.after(to_freq)\n\n        to_freq.append_tail(node)\n\n        if from_freq.freq != 0 and from_freq.is_empty():\n            from_freq.unlink()\n\n    def _evict_word(self):\n        # update self.words\n        node = self.words[0].nxt\n        node.unlink()\n        word = node.word\n\n        # update self.freqs\n        node = self.nodes[word]\n        from_freq = node.freq_node\n        to_freq = None\n        node.unlink()\n\n        if from_freq.freq == 1:\n            self.nodes[word] = None\n            if from_freq.is_empty():\n                from_freq.unlink()\n            return\n\n        if from_freq.pre.freq == from_freq.freq - 1:\n            to_freq = from_freq.pre\n        else:\n            to_freq = FreqNode(from_freq.freq - 1)\n            from_freq.before(to_freq)\n\n        to_freq.append_tail(node)\n\n        if from_freq.is_empty():\n            from_freq.unlink()\n\n\nclass WordNode:\n    def __init__(self, word, freq_node=None, pre=None, nxt=None):\n        self.word = word\n        self.freq_node = freq_node\n        self.pre = pre\n        self.nxt = nxt\n\n    def link(self, pre, nxt):\n        self.pre = pre\n        self.nxt = nxt\n        pre.nxt = self\n        nxt.pre = self\n\n    def unlink(self):\n        self.pre.nxt = self.nxt\n        self.nxt.pre = self.pre\n        self.pre = self.nxt = self.freq_node = None\n\n\nclass FreqNode:\n    def __init__(self, freq, pre=None, nxt=None):\n        self.freq = freq\n        self.pre = pre\n        self.nxt = nxt\n        self.words = (WordNode(''), WordNode(''))  # D, d for words list\n        self.words[0].nxt = self.words[1]\n        self.words[1].pre = self.words[0]\n\n    def unlink(self):\n        self.pre.nxt = self.nxt\n        self.nxt.pre = self.pre\n        self.pre = self.nxt = self.words = None\n\n    def before(self, freq_node):\n        freq_node.pre = self.pre\n        freq_node.nxt = self\n        self.pre.nxt = freq_node\n        self.pre = freq_node\n\n    def after(self, freq_node):\n        freq_node.pre = self\n        freq_node.nxt = self.nxt\n        self.nxt.pre = freq_node\n        self.nxt = freq_node\n\n    def is_empty(self):\n        return self.words[0].nxt is self.words[1]\n\n    def append_tail(self, word_node):\n        word_node.freq_node = self\n        word_node.pre = self.words[1].pre\n        word_node.nxt = self.words[1]\n        self.words[1].pre.nxt = word_node\n        self.words[1].pre = word_node\n\n\nif __name__ == '__main__':\n    s = Solution(8)\n    _in, _out = 'ABABCCCBAC', 'ABABBCCBBC'\n    gotcha = []\n\n    for i in range(len(_in)):\n        gotcha.append(s.insert(_in[i]) is None)\n        res = s.get_most_popular_word()\n        if res != _out[i]: print(_in, i, _in[i], res)\n        gotcha.append(res == _out[i])\n\n    print(bool(gotcha) and all(gotcha))\n"
  },
  {
    "path": "other/guess_secret.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for words, _out in (\n...     (['apple', 'price', 'tuple', 'agile'], 'apple'),\n...     (['apple', 'apple', 'apple', 'apple'], 'apple'),\n...     (['aa', 'ab', 'ac', 'ad', 'ae', 'af', 'ag'], 'ae'),\n...     (['aa', 'ab', 'ac', 'ad', 'ae', 'af', 'ag'], 'ag'),\n...     (['aa', 'ab', 'ab', 'ac'], 'ab'),\n... ):\n...     secret = Secret(_out)\n...     res = find_secret(secret, words)\n...     if res != _out: print(words, res, secret.score)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef find_secret(secret, words):\n    if not isinstance(secret, Secret):\n        return ''\n\n    while len(words) > 1:\n        has_got, correct_cnt = secret.guess(words[-1])\n        guess_word = words.pop()\n\n        if has_got:\n            return guess_word\n\n        _words = []\n        n = len(guess_word)\n\n        for word in words:\n            cnt = 0\n\n            for i in range(n):\n                if word[i] == guess_word[i]:\n                    cnt += 1\n\n            if cnt == len(word):\n                return word\n            if cnt == correct_cnt:\n                _words.append(word)\n\n        words = _words\n\n    return words[0]\n\n\nclass Secret:\n    def __init__(self, word):\n        self.secret = word\n        self.score = 0\n\n    def guess(self, word):\n        if not word or len(word) != len(self.secret):\n            return\n\n        cnt = 0\n\n        for i in range(len(word)):\n            if word[i] == self.secret[i]:\n                cnt += 1\n\n        self.score -= 1\n\n        return [cnt == len(word), cnt]\n"
  },
  {
    "path": "other/inorder_non_threaded_binary_tree_traversal.py",
    "content": "\"\"\"\nInorder Traversal in Binary Tree\nwithout Recursion or Stack or Modification\n\nRecursion: The simplest way\nIteration: With Stack\nMorris Traversal: With Modification\n\nAnd the following code is for the 4th way\nto inorder traverse binary tree\nif we have parent pointers available to us.\n\nREF: Inorder Non-threaded Binary Tree Traversal without Recursion or Stack\nhttps://www.geeksforgeeks.org/inorder-non-threaded-binary-tree-traversal-without-recursion-or-stack/\n\n\nNode Structure:\n\n>>> class TreeNode:\n...     def __init__(self, val, left=None, right=None, parent=None):\n...         self.val = val\n...         self.left = left\n...         self.right = right\n...         self.parent = parent\n\n\nProcess:\n\n0. go_left = True\n1. keep moving to the most left\n2. print val\n3. if has right child, move on it. and go_left = True to repeat (1)\n4. keep moving to the most parent\n   if no right and its just the right of its parent\n5. move one more to its parent and go_left = False\n\n\nTesting:\n\n>>> trees = []\n>>> tree_infos = [\n...     ((\n...         (1, None, None, 2),\n...         (2, 1, None, None),\n...     ), '1,2'),\n...     ((\n...         (20, None, 8, 22),\n...         (8, 20, 4, 12),\n...         (22, 20, None, None),\n...         (4, 8, None, None),\n...         (12, 8, 10, 14),\n...         (10, 12, None, None),\n...         (14, 12, None, None),\n...     ), '4,8,10,12,14,20,22'),\n...     ((\n...         (10, None, 5, 100),\n...         (5, 10, None, None),\n...         (100, 10, 80, 120),\n...         (80, 100, None, None),\n...         (120, 100, None, None),\n...     ), '5,10,80,100,120'),\n...     ((\n...         (1, None, 2, 3),\n...         (2, 1, 4, None),\n...         (3, 1, None, 5),\n...         (4, 2, None, 6),\n...         (5, 3, None, None),\n...         (6, 4, 7, 8),\n...         (7, 6, None, None),\n...         (8, 6, None, None),\n...     ), '4,7,6,8,2,1,3,5'),\n...     ((\n...         (1, None, None, 2),\n...         (2, 1, None, 3),\n...         (3, 2, None, 4),\n...         (4, 3, None, 5),\n...         (5, 4, None, 6),\n...         (6, 5, None, 7),\n...         (7, 6, None, None),\n...     ), '1,2,3,4,5,6,7'),\n... ]\n\n>>> for info, _ in tree_infos:\n...     nodes = {node[0]: TreeNode(node[0]) for node in info}\n...\n...     for val, parent, left, right in info:\n...         if parent:\n...             nodes[val].parent = nodes[parent]\n...         if left:\n...             nodes[val].left = nodes[left]\n...         if right:\n...             nodes[val].right = nodes[right]\n...\n...     trees.append(nodes[info[0][0]])\n\n>>> gotcha = []\n\n>>> for i in range(len(trees)):\n...     res = []\n...     inorder_traverse(trees[i], callback=lambda val: res.append(str(val)))\n...     gotcha.append(','.join(res) == tree_infos[i][1])\n\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef inorder_traverse(root, *, callback):\n    go_left = True\n\n    while root:\n        while go_left and root.left:\n            root = root.left\n\n        callback(root.val)\n\n        if root.right:\n            root = root.right\n            go_left = True\n            continue\n\n        # if no right child,\n        # and its just a right child of its parent\n        while root.parent and root is root.parent.right:\n            root = root.parent\n\n        root = root.parent\n        go_left = False\n"
  },
  {
    "path": "other/is_valid_relation.py",
    "content": "\"\"\"\nQuestion:\n\nThe rules look like this:\n'A NE B' - means this means point A is located northeast of point B.\n'A SW C' - means that point A is southwest of C.\n'A N D' - means that point A is north of D but maybe true north, northeast, or northwest.\n\nGiven a list of rules, check if the sum of the rules validates. For example:\n['A N B', 'B NE C', 'C N A'], returns False\n['A N B', 'B NE C', 'C S A'], returns True\n\n\nTesting:\n\n>>> gotcha = []\n>>> for _in, _out in (\n...     ([], False),\n...     ([''], False),\n...     (['A N B', 'B NE C', 'C N A'], False),\n...     (['A N B', 'B NW C', 'C N C'], False),\n...     (['A N B', 'B N C', 'C N B'], False),\n...     (['A N B', 'B NE C', 'C S A'], True),\n...     (['A N B', 'B NW C', 'C S A'], True),\n...     (['A E B', 'B E C', 'C S D', 'D S E'], True),\n...     (['A N B', 'B S A', 'C E D', 'D W C'], True),\n... ):\n...     res = is_valid_relation(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\nimport collections\n\n\ndef is_valid_relation(strs):\n    \"\"\"\n    :type strs: list[str]\n    :rtype: bool\n    \"\"\"\n    if not strs:\n        return False\n\n    # egraph => scan from east to west\n    egraph = collections.defaultdict(set)\n    wgraph = collections.defaultdict(set)\n    ngraph = collections.defaultdict(set)\n    sgraph = collections.defaultdict(set)\n\n    for s in strs:\n        if not s:\n            return False\n\n        dst, d, src = s.split()\n\n        if 'E' in d:\n            egraph[dst].add(src)\n            wgraph[src].add(dst)\n        elif 'W' in d:\n            wgraph[dst].add(src)\n            egraph[src].add(dst)\n\n        if 'N' in d:\n            ngraph[dst].add(src)\n            sgraph[src].add(dst)\n        elif 'S' in d:\n            sgraph[dst].add(src)\n            ngraph[src].add(dst)\n\n    for graph in (egraph, wgraph, ngraph, sgraph):\n        for node in graph.keys():\n            if dfs(graph, node, set()):\n                return False\n\n    return True\n\n\ndef dfs(graph, node, visited):\n    \"\"\"\n    returns True if there is cycle in graph\n    :type graph: dict{str: set}\n    :type node: str\n    :type visited: set\n    :rtype: bool\n    \"\"\"\n    if node not in graph:\n        return False\n    if node in visited:\n        return True\n\n    visited.add(node)\n\n    for nxt in graph[node]:\n        if dfs(graph, nxt, visited):\n            return True\n\n    return False\n"
  },
  {
    "path": "other/merge_mail.py",
    "content": "def merge_mail(data):\n    \"\"\"group owners if their mails got a connection\n    >>> merge_mail({\n    ...     'A1': ['a1@gmail.com', 'a2@gmail.com'],\n    ...     'A2': ['b1@gmail.com', 'a2@gmail.com'],\n    ...     'A3': ['c1@gmail.com'],\n    ...     'A4': ['c1@gmail.com', 'd1@gmail.com'],\n    ...     'A5': ['b1@gmail.com', 'e1@gmail.com'],\n    ... })\n    [['A1', 'A2', 'A5'], ['A3', 'A4']]\n\n    >>> merge_mail({\n    ...     'A1': ['a1@gmail.com', 'a2@gmail.com'],\n    ...     'A2': ['b1@gmail.com', 'a2@gmail.com'],\n    ...     'A3': ['b1@gmail.com', 'c1@gmail.com'],\n    ...     'A4': ['c1@gmail.com', 'd1@gmail.com'],\n    ...     'A5': ['b1@gmail.com', 'e1@gmail.com'],\n    ... })\n    [['A1', 'A2', 'A3', 'A4', 'A5']]\n    \"\"\"\n    owners = {}  # owners\n    mail2owners = {}  # mail to owners\n\n    for owner, mails in data.items():\n        find(owners, owner)\n        for mail in mails:\n            if mail not in mail2owners:\n                mail2owners[mail] = owner\n                continue\n            mail2owners[mail] = connect(\n                owners, owner, mail2owners[mail]\n            )\n\n    ans = {}\n    for k, v in owners.items():\n        if v not in ans:\n            ans[v] = []\n        ans[v].append(k)\n    return list(ans.values())\n\ndef connect(nodes, a, b):\n    _a = find(nodes, a)\n    _b = find(nodes, b)\n    if _a is not _b:\n        nodes[_a] = _b\n    return _b\n\ndef find(nodes, a):\n    if a not in nodes:\n        nodes[a] = a\n        return a\n    if nodes[a] is a:\n        return a\n    nodes[a] = find(nodes, nodes[a])\n    return nodes[a]\n"
  },
  {
    "path": "other/reservation.py",
    "content": "\"\"\"\nOO Design\n设计一个剧院的订座系统，user一次可以query不多于5个座位，\n这个系统要能return相应数量并尽可能相连的座位。\n用户可以选择订或不订这些位子，订的话这些位子就不available了，\n没订的话位子就都还available，\n但要求这位用户下次query还是return这些位子（防止用户不停刷系统以拿到他们想要的位子），\n除非下次query前这些位子里k个被别人订了，那系统再生成k个available的位子。\n\nMy understanding\nr1 => 尽可能相连的座位 => MUST be in same row\nr2 => requery => same seats if seats are also available,\n    otherwise find new available seats and still follow (r1)\n\"\"\"\n\n\nclass Reservation:\n    def __init__(self, m, n):\n        pass\n\n    def get_seats(self, user_id, n=0):\n        pass\n"
  },
  {
    "path": "other/robot_cleaner.py",
    "content": "\"\"\"\nGiven a robot cleaner in a room modeled as a grid.\nEach cell in the grid can be empty or blocked.\nThe robot cleaner with 4 given APIs can move forward, turn left or turn right.\nWhen it tries to move into a blocked cell,\nits bumper sensor detects the obstacle and it stays on the current cell.\n\nThe 4 APIs are:\nclean(): clean the current location.\nturnleft(k=1): turn left k*90 degrees.\nturnrigt(k=1): turn right k*90 degrees.\nmove(direction=None): move forward for 1 position, return False if that’s not possible.\n\n- How do you clean the entire space?\n- How long will it take? (1 step == 1 time unit)\n- Can you show paths?\n\n\nNeed to ask:\n\n- is there an api to detect the cell need to clean?\n- are both the robot's direction and coordinate need to same as room?\n- once we called the `move` api and passed a direction.\n  will the robot turn its face in that direction?\n  and move forward with 1 unit?\n\n\nREF:\n\n- http://www.hoangvancong.com/2016/10/28/bfs-backtrack-robot-don-dep-cleaning-robot\n- https://blog.csdn.net/aozil_yang/article/details/52177644\n- http://www.1point3acres.com/bbs/thread-289514-1-1.html\n- http://www.1point3acres.com/bbs/thread-345555-1-1.html\n\n\nTesting:\n\n1. is the mock api working?\n\n>>> room = Room([\n...     [0, 0, 0, 0, 0, 0, 0, 0],\n...     [0, 0, 0, 1, 0, 0, 0, 0],\n...     [0, 2, 0, 0, 0, 0, 0, 0],\n...     [2, 2, 2, 0, 2, 2, 2, 2],\n...     [0, 0, 0, 0, 0, 0, 0, 3],\n... ])\n>>> robot = Robot(room)\n>>> all((\n...     room._get_robot() == (4, 7),\n...     robot._get_face() == Dirs.DOWN,\n...     robot.move() is False,\n...     robot.turnleft() is None,\n...     robot.move() is False,\n...     robot.turnrigt() is None,\n...     robot.move() is False,\n...     robot.turnleft(3) is None,\n...     robot.move() is True,\n...     room._get_robot() == (4, 6),\n... ))\nTrue\n>>> all((\n...     robot.move() is True,\n...     robot.move(Dirs.LEFT) is True,\n...     robot.turnleft(2) is None,\n...     robot.turnrigt(2) is None,\n...     robot.move() is True,\n...     room._get_robot() == (4, 3),\n... ))\nTrue\n>>> all((\n...     robot._get_face() == Dirs.LEFT,\n...     robot.move(Dirs.UP) is True,\n...     robot.turnleft() is None,\n...     robot.move() is False,\n...     robot.turnrigt(2) is None,\n...     robot.move() is False,\n...     robot.turnleft() is None,\n... ))\nTrue\n>>> all((\n...     robot.move() is True,\n...     robot.turnleft() is None,\n...     robot.move() is True,\n...     robot.move() is False,\n...     robot.move() is False,\n...     robot.move() is False,\n...     robot.turnrigt() is None,\n...     robot.move() is True,\n...     robot.turnrigt() is None,\n... ))\nTrue\n>>> all((\n...     room._get_robot() == (1, 2),\n...     robot.move() is True,\n...     room.is_clear() is False,\n...     robot.clean() is None,\n...     room.is_clear() is True,\n...     robot.clean() is None,\n...     room.is_clear() is True,\n...     room.is_clear() is True,\n... ))\nTrue\n\n2. test cleaner\n\n>>> CASES = (\n...     (\n...         (3, 0, 0, 0, 0, 0, 1, 0),\n...         (0, 0, 0, 0, 0, 0, 0, 0),\n...         (0, 2, 0, 0, 0, 0, 0, 0),\n...         (2, 2, 2, 0, 2, 2, 2, 2),\n...         (0, 0, 1, 0, 0, 0, 1, 0),\n...     ),\n...     (\n...         (0, 0, 0, 0, 0, 0, 0, 0),\n...         (0, 0, 1, 0, 2, 0, 0, 0),\n...         (1, 2, 0, 0, 2, 1, 0, 0),\n...         (2, 2, 2, 0, 2, 2, 2, 2),\n...         (1, 0, 0, 0, 0, 0, 0, 3),\n...     ),\n...     (\n...         (1, 0, 0, 0, 0, 0, 0, 1),\n...         (0, 0, 0, 1, 0, 0, 0, 0),\n...         (0, 2, 0, 0, 0, 0, 1, 0),\n...         (2, 2, 2, 0, 2, 2, 2, 2),\n...         (0, 1, 0, 3, 0, 1, 0, 1),\n...     ),\n...     (\n...         (0, 0, 0, 0, 0, 0, 0, 1),\n...         (0, 0, 0, 1, 2, 0, 3, 0),\n...         (0, 2, 0, 0, 2, 1, 0, 0),\n...         (2, 2, 2, 1, 2, 2, 2, 2),\n...         (0, 1, 0, 0, 1, 0, 0, 1),\n...     ),\n... )\n\n>>> cleaners = (\n...     RobotCleanerDFS(),\n...     RobotCleanerDFS2(),\n...     # RobotCleanerBFS(),\n... )\n\n>>> gotcha = []\n>>> for grid in CASES:\n...     for cleaner in cleaners:\n...         room = Room([list(r) for r in grid])\n...         robot = Robot(room)\n...\n...         gotcha.append(not room.is_clear())\n...         cleaner.clean_room(robot)\n...\n...         if not room.is_clear(): room._print_room(); print(cleaner)\n...         gotcha.append(room.is_clear())\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\nclass Dirs:\n    \"\"\"\n    The directions should be in order\n    to make turnleft/right in Robot more convient\n    if need 8-dirs, the order becomes:\n    D, DR, R, UR, U, UL, L, DL\n    \"\"\"\n    DOWN = 0\n    RIGHT = 1\n    UP = 2\n    LEFT = 3\n    DELTA = (\n        ( 1,  0),\n        ( 0,  1),\n        (-1,  0),\n        ( 0, -1),\n    )\n\n\nclass Room:\n    EMPTY = 0\n    CLEANUP = 1\n    OBSTACLE = 2\n    ROBOT = 3\n\n    def __init__(self, grid):\n        \"\"\"\n        :type grid: list[list[int]]\n        \"\"\"\n        self.__room = grid\n        self.__cleanups = 0\n        self.__robot_at = (0, 0)\n\n        m, n = len(grid), len(grid[0])\n\n        for x in range(m):\n            for y in range(n):\n                if grid[x][y] == self.CLEANUP:\n                    self.__cleanups += 1\n                elif grid[x][y] == self.ROBOT:\n                    grid[x][y] = self.EMPTY\n                    self.__robot_at = (x, y)\n\n    def is_clear(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.__cleanups == 0\n\n    def move_robot(self, direction):\n        \"\"\"\n        :type direction: int, defined in Dirs\n        :rtype: bool\n        \"\"\"\n        m, n = len(self.__room), len(self.__room[0])\n        x, y = self.__robot_at\n        dx, dy = Dirs.DELTA[direction]\n        _x, _y = x + dx, y + dy\n\n        if not (0 <= _x < m and 0 <= _y < n):\n            return False\n\n        if self.__room[_x][_y] == self.OBSTACLE:\n            return False\n\n        self.__robot_at = (_x, _y)\n        return True\n\n    def clean(self, robot):\n        \"\"\"\n        :type robot: Robot\n        :rtype: void\n        \"\"\"\n        if not isinstance(robot, Robot):\n            return\n\n        x, y = self.__robot_at\n\n        if self.__room[x][y] == self.CLEANUP:\n            self.__room[x][y] = self.EMPTY\n            self.__cleanups -= 1\n\n    def _get_robot(self):\n        # for testing\n        return self.__robot_at\n\n    def _print_room(self):\n        # for testing\n        print(\n            '\\n'.join(str(r) for r in self.__room),\n            '\\nRobot at: ', self.__robot_at,\n            '\\nCleanups: ', self.__cleanups,\n            '\\n'\n        )\n\n\nclass Robot:\n    def __init__(self, room):\n        \"\"\"\n        :type room: Room\n        \"\"\"\n        self.__room = room\n        self.__face = Dirs.DOWN\n\n    def move(self, direction=None):\n        \"\"\"\n        :type direction: int, defined in Dirs\n        :rtype: bool\n        \"\"\"\n        if direction in range(len(Dirs.DELTA)):\n            self.__face = direction\n\n        return self.__room.move_robot(self.__face) is True\n\n    def turnleft(self, k=1):\n        \"\"\"\n        :type k: int\n        :rtype: void\n        \"\"\"\n        n = len(Dirs.DELTA)\n        self.__face = (self.__face + k) % n\n\n    def turnrigt(self, k=1):\n        \"\"\"\n        :type k: int\n        :rtype: void\n        \"\"\"\n        # note that, -1 % 4 == 3 in Python, or just (x - k + n) % n\n        n = len(Dirs.DELTA)\n        self.__face = (self.__face - k) % n\n\n    def clean(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        self.__room.clean(self)\n\n    def _get_face(self):\n        # for testing\n        return self.__face\n\n\nclass RobotCleanerDFS:\n    \"\"\"\n    this approach is for we need to adjust `dir` manually\n    the `robot.move()` only can move forward with 1 step\n    \"\"\"\n    def clean_room(self, robot):\n        \"\"\"\n        :type robot: Robot\n        \"\"\"\n        if not isinstance(robot, Robot):\n            return\n\n        \"\"\"\n        robot's direction and coord no needs to same as room\n        just start as (0, 0),\n        and face 0 (this 0 just ref of dirs, no needs to treat it as Dirs.DOWN)\n\n        Dirs.DELTA => D, R, U, L\n        (1, 0), (0, 1), (-1, 0), (0, -1)\n        \"\"\"\n        self.dfs(0, 0, 0, robot, set())\n\n    def dfs(self, x, y, to_dir, robot, visited):\n        robot.clean()\n        visited.add((x, y))\n\n        # down\n        d = to_dir\n        _x = x + Dirs.DELTA[d][0]\n        _y = y + Dirs.DELTA[d][1]\n\n        if (_x, _y) not in visited and robot.move():\n            self.dfs(_x, _y, d, robot, visited)\n            robot.turnrigt()\n        else:\n            robot.turnleft()\n\n        # right\n        d = (to_dir + 1) % len(Dirs.DELTA)\n        _x = x + Dirs.DELTA[d][0]\n        _y = y + Dirs.DELTA[d][1]\n\n        if (_x, _y) not in visited and robot.move():\n            self.dfs(_x, _y, d, robot, visited)\n        else:\n            robot.turnleft(2)\n\n        # left\n        d = (to_dir + 3) % len(Dirs.DELTA)\n        _x = x + Dirs.DELTA[d][0]\n        _y = y + Dirs.DELTA[d][1]\n\n        if (_x, _y) not in visited and robot.move():\n            self.dfs(_x, _y, d, robot, visited)\n            robot.turnleft()\n        else:\n            robot.turnrigt()\n\n        # up\n        d = (to_dir + 2) % len(Dirs.DELTA)\n        _x = x + Dirs.DELTA[d][0]\n        _y = y + Dirs.DELTA[d][1]\n\n        if (_x, _y) not in visited and robot.move():\n            self.dfs(_x, _y, d, robot, visited)\n            robot.turnrigt(2)\n\n        # move robot when the recursion is back\n        robot.move()\n\n\nclass RobotCleanerDFS2:\n    \"\"\"\n    this approach is for we can just pass `dir` into `robot.move(dir)`\n    \"\"\"\n    def clean_room(self, robot):\n        \"\"\"\n        :type robot: Robot\n        \"\"\"\n        if not isinstance(robot, Robot):\n            return\n\n        \"\"\"\n        robot's direction and coord no needs to same as room\n        just start as (0, 0),\n        and face 0 (this 0 just ref of dirs, no needs to treat it as Dirs.DOWN)\n        \"\"\"\n        self.dfs(0, 0, 0, robot, set())\n\n    def dfs(self, x, y, from_dir, robot, visited):\n        # is there a api to detect the cell need to clean?\n        robot.clean()\n        visited.add((x, y))\n\n        for to_dir in range(len(Dirs.DELTA)):\n            if to_dir == from_dir:\n                continue\n\n            # to_dir is index and also the direction defined in Dirs\n            dx, dy = Dirs.DELTA[to_dir]\n            _x = x + dx\n            _y = y + dy\n\n            if (_x, _y) in visited:\n                continue\n\n            if robot.move(to_dir):\n                self.dfs(_x, _y, (to_dir + 2) % len(Dirs.DELTA), robot, visited)\n            else:\n                visited.add((_x, _y))\n\n        robot.move(from_dir)\n\n\nclass RobotCleanerBFS:\n    def clean_room(self, robot):\n        \"\"\"\n        :type robot: Robot\n        \"\"\"\n        if not isinstance(robot, Robot):\n            return\n\n    def bfs(self):\n        pass\n\n\nif __name__ == '__main__':\n    # for debugging\n    room = Room([\n        [1, 0, 0, 0, 0, 0, 0, 1],\n        [0, 0, 0, 1, 0, 0, 0, 0],\n        [0, 2, 0, 0, 0, 0, 1, 0],\n        [2, 2, 2, 0, 2, 2, 2, 2],\n        [0, 1, 0, 3, 0, 1, 0, 1],\n    ])\n    robot = Robot(room)\n    s = RobotCleanerDFS()\n\n    room._print_room()\n    s.clean_room(robot)\n    room._print_room()\n"
  },
  {
    "path": "other/snake_and_ladder_problem.py",
    "content": "\"\"\"\nProblem: https://www.geeksforgeeks.org/snake-ladder-problem-2/\n\"\"\"\n\n\ndef get_min_dice_throws(moves):\n    \"\"\"\n    :type moves: list[int]\n    :type n: int\n    :rtype: int\n\n    >>> moves = [-1] * 30\n    >>> for i, val in (\n    ...     # ladders\n    ...     ( 2, 21),\n    ...     ( 4,  7),\n    ...     (10, 25),\n    ...     (19, 28),\n    ...     # snakes\n    ...     (26,  0),\n    ...     (20,  8),\n    ...     (16,  3),\n    ...     (18,  6),\n    ... ):\n    ...     moves[i] = val\n    >>> get_min_dice_throws(moves)\n    3\n    \"\"\"\n    if not moves:\n        return -1\n\n    n = len(moves)\n    queue, _queue = [0], []\n    steps = {0: 0}  # min steps to get i\n\n    while queue:\n        for i in queue:\n            for j in range(i + 1, min(i + 7, n)):\n                # 6-faced dice => max 6 steps but up to n\n                if j == n - 1:\n                    return steps[i]\n\n                if j in steps:\n                    # is visited\n                    continue\n\n                # next cell\n                k = moves[j] if moves[j] != -1 else j\n                steps[k] = steps[i] + 1\n                _queue.append(k)\n\n        queue, _queue = _queue, []\n\n    return -1\n"
  },
  {
    "path": "other/stock_stream.py",
    "content": "class StockStream:\n    def __init__(self, prices):\n        pass\n\n    def update(self, timestamp, price):\n        \"\"\"\n        :type timestamp: int\n        :type price: int\n        :rtype: void\n        \"\"\"\n        pass\n\n    def get_highest(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        pass\n\n    def get_lowest(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        pass\n\n    def get_latest(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        pass\n"
  },
  {
    "path": "other/string_abbreviation.py",
    "content": "\"\"\"\nThis problem should be discussed, and there might be 3 ways to solve\nREF: http://www.1point3acres.com/bbs/thread-218909-1-1.html\n\n1. add specific char to separate. '@'\n2. encode number anyway\n3. cheating, like '1aaaaa' -> '1a4xa'\n\n\n>>> CASE = (\n...     ('ff', 'ff'),\n...     ('fff', 'fff'),\n...     ('ffff', '4xf'),\n...     ('1xt', '1x1xt'),\n...     ('5xt', '1x5xt'),\n...     ('1aaaaa', '1x15xa'),\n...     ('3aaaaa', '1x35xa'),\n...     ('123aaaa', '1x11x21x34xa'),\n...     ('aaabbbbcccc', 'aaa4xb4xc'),\n... )\n\n>>> all(decode(encode(inpt)) == inpt for inpt, _ in CASE)\nTrue\n>>> all(encode(inpt) == oupt for inpt, oupt in CASE)\nTrue\n>>> all(decode(oupt) == inpt for inpt, oupt in CASE)\nTrue\n\"\"\"\n\n\ndef encode(s):\n    \"\"\"\n    :type s: str\n    :rtype: str\n    \"\"\"\n    if not s:\n        return ''\n\n    res = []\n    cnt = 1\n    char = s[0]\n\n    for i in range(1, len(s)):\n        if s[i] == s[i - 1]:\n            cnt += 1\n            continue\n\n        # s[i] != s[i - 1]\n        if char.isdigit() or cnt > 3:\n            res.append(str(cnt))\n            res.append('x')\n            res.append(char)\n        else:\n            res.append(char * cnt)\n\n        cnt = 1\n        char = s[i]\n\n    if char.isdigit() or cnt > 3:\n        res.append(str(cnt))\n        res.append('x')\n        res.append(char)\n    else:\n        res.append(char * cnt)\n\n    return ''.join(res)\n\n\ndef decode(s):\n    \"\"\"\n    :type s: str\n    :rtype: str\n    \"\"\"\n    if not s:\n        return ''\n\n    res = []\n    i = 0\n    n = len(s)\n\n    while i < n:\n        is_digit = s[i].isdigit()\n\n        if is_digit and i + 2 >= n:\n            return ''\n\n        if is_digit:\n            res.append(int(s[i]) * s[i + 2])\n            i += 3\n        else:\n            res.append(s[i])\n            i += 1\n\n    return ''.join(res)\n"
  },
  {
    "path": "other/the_point_inside_polygon.py",
    "content": "\"\"\"\nQuestions:\n1. Choose a random point from one single rectangle.\n    => get_random_point_inside_rectangle\n2. Choose a random point from multiple rectangles, if there is no overlapping among them.\n    => get_random_point_inside_rectangle2\n3. Choose a random point from multiple rectangles, if there is overlapping among them.\n    => get_random_point_inside_rectangle3\n4. Is a point inside polygon?\n    => is_point_inside_polygon\n\n* p.s. overlapping means the point\n    - was shared between two recs\n    - even the point is a vertex or on edge.\n\"\"\"\nimport random\n\n\ndef get_random_point_inside_rectangle(rectangle):\n    \"\"\"\n    :type rectangle: list[int]\n    :rtype: list[int]\n    \"\"\"\n    if not rectangle:\n        return []\n\n    x1, y1, x2, y2 = rectangle\n\n    return [\n        random.randint(x1, x2),\n        random.randint(y2, y1),\n    ]\n\n# ======\n\n\ndef get_random_point_inside_rectangle2(rectangles):\n    \"\"\"\n    :type rectangles: list[list[int]]\n    :rtype: list[int]\n    \"\"\"\n    if not rectangles:\n        return []\n\n    k = total = 0\n\n    for i in range(len(rectangles)):\n        x1, y1, x2, y2 = rectangles[i]\n        area = (x2 - x1) * (y1 - y2)\n\n        if random.randrange(total + area) >= total:\n            k = i\n\n        total += area\n\n    return get_random_point_inside_rectangle(rectangles[k])\n\n# ======\n\n\ndef get_random_point_inside_rectangle3(rectangles):\n    \"\"\"\n    :type rectangles: list[list[int]]\n    :rtype: list[int]\n    \"\"\"\n    if not rectangles:\n        return []\n\n# ======\n\n\ndef is_point_inside_polygon(polygon, point):\n    \"\"\"\n    :type polygon: list[list[int]]\n    :type point: list[int]\n    :rtype: bool\n    \"\"\"\n    if not polygon or not point or len(polygon) < 3:\n        return False\n\n# ======\n\n\nif __name__ == '__main__':\n    import collections\n\n    gotcha = []\n\n    # single-rec\n    freq = collections.defaultdict(int)\n    for _ in range(10000):\n        x, y = get_random_point_inside_rectangle((0, 2, 3, 0))\n        freq[x, y] += 1\n    gotcha.append(len(freq) == 12)\n    gotcha.append(all(633 <= fq <= 1033 for fq in freq.values()))\n\n    # multi-recs, no overlapping\n    freq = collections.defaultdict(int)\n    for _ in range(10000):\n        x, y = get_random_point_inside_rectangle2((\n            (0, 2, 1, 0),\n            (2, 2, 3, 0),\n        ))\n        freq[x, y] += 1\n    gotcha.append(len(freq) == 12)\n    gotcha.append(all(633 <= fq <= 1033 for fq in freq.values()))\n\n    # # multi-recs, overlapping\n    # freq = collections.defaultdict(int)\n    # for _ in range(100000):\n    #     x, y = get_random_point_inside_rectangle3((\n    #         (3, 3, 7, -4),\n    #         (-4, 5, 1, -2),\n    #         (-2, 7, 5, 1),\n    #     ))\n    #     freq[x, y] += 1\n    # gotcha.append(len(freq) == 115)\n    # gotcha.append(all(469 <= fq <= 1269 for fq in freq.values()))\n\n    # # multi-recs, overlapping\n    # freq = collections.defaultdict(int)\n    # for _ in range(100000):\n    #     x, y = get_random_point_inside_rectangle3((\n    #         (-6, 2, 0, -4),\n    #         (-2, 4, 4, -2),\n    #         (-4, 6, 2, 0),\n    #     ))\n    #     freq[x, y] += 1\n    # gotcha.append(len(freq) == 101)\n    # gotcha.append(all(590 <= fq <= 1390 for fq in freq.values()))\n\n    # for _in, _out in (\n    #     (([[0, 0], [10, 0], [10, 10], [0, 10]], [20, 20]), False),\n    #     (([[0, 0], [10, 0], [10, 10], [0, 10]], [5, 5]), True),\n    #     (([[0, 0], [5, 5], [5, 0]], [3, 3]), False),\n    #     (([[0, 0], [5, 5], [5, 0]], [5, 1]), False),\n    #     (([[0, 0], [5, 5], [5, 0]], [8, 1]), False),\n    #     (([[0, 0], [10, 0], [10, 10], [0, 10]], [-1, 10]), False),\n    #     (([[2, 1], [3, 2], [2, 3]], [1, 2]), False),\n    #     (([[0, 0], [5, 0], [10, 10], [5, 10]], [3, 3]), True),\n    #     (([[0, 0], [5, 0], [10, 10], [5, 10]], [4, 10]), False),\n    #     (([[0, 0], [-5, 0], [-10, -10]], [0, -2]), False),\n    #     (([[2, 5], [5, 0], [8, 5], [5, 10]], [0, 0]), False),\n    #     (([[2, 5], [5, 0], [8, 5], [5, 10]], [5, 5]), True),\n    # ):\n    #     res = is_point_inside_polygon(*_in)\n    #     if res != _out: print(_in, res)\n    #     gotcha.append(res == _out)\n\n    print(bool(gotcha) and all(gotcha))\n"
  },
  {
    "path": "other/uneven_random_get.py",
    "content": "\"\"\"\nTODO:\n1. do expectations like `chi-square calculator`\n\"\"\"\nimport random\n\n\ndef uneven_random_get(options, rate):\n    \"\"\"unevenly fetch the option according to the corresponding rate\n    :type options: list[str]\n    :type rate: list[num]\n    :rtype: str\n    \"\"\"\n    if not options or not rate or len(options) != len(rate):\n        return ''\n\n    num = 0\n    rand = random.randint(1, sum(rate))\n\n    for i in range(len(rate)):\n        num += rate[i]\n\n        if num >= rand:\n            return options[i]\n\n    return options[0]\n\n\ndef uneven_random_get2(options, rate):\n    \"\"\"unevenly fetch the option according to the corresponding rate\n    :type options: list[str]\n    :type rate: list[num]\n    :rtype: str\n    \"\"\"\n    if not options or not rate or len(options) != len(rate):\n        return ''\n\n    k = total = 0\n\n    for i in range(len(rate)):\n        if random.randrange(total + rate[i]) >= total:\n            k = i\n\n        total += rate[i]\n\n    return options[k]\n\n\nif __name__ == '__main__':\n    gotcha = []\n    options = 'abc'\n\n    for uneven_get in (uneven_random_get, uneven_random_get2):\n        freq = dict.fromkeys(options, 0)\n        for _ in range(10000):\n            c = uneven_get(options, (10, 10, 10))\n            freq[c] += 1\n        gotcha.append(all(2833 <= freq[c] <= 3833 for c in options))\n\n        freq = dict.fromkeys(options, 0)\n        for _ in range(10000):\n            c = uneven_get(options, (1, 1, 1))\n            freq[c] += 1\n        gotcha.append(all(2833 <= freq[c] <= 3833 for c in options))\n\n        freq = dict.fromkeys(options, 0)\n        for _ in range(10000):\n            c = uneven_get(options, (8, 1, 1))\n            freq[c] += 1\n        gotcha.append(all((\n            7500 <= freq['a'] <= 8500,\n            500 <= freq['b'] <= 1500,\n            500 <= freq['c'] <= 1500,\n        )))\n\n    print(bool(gotcha) and all(gotcha))\n"
  },
  {
    "path": "other/unique_paths_with_followups.py",
    "content": "\"\"\"\n给定一个矩形的宽和长，求所有可能的路径数量\n\nRules：\n1. 从左上角走到右上角\n2. 要求每一步只能向正右、右上或右下走，即 →↗↘\n\nfollowup1: 优化空间复杂度至 O(n)\nfollowup2: 给定矩形里的三个点，判断是否存在遍历这三个点的路经\nfollowup3: 给定矩形里的三个点，找到遍历这三个点的所有路径数量\nfollowup4: 给定一个下界 (x == H)，找到能经过给定下界的所有路径数量 (x >= H)\nfollowup5: 起点和终点改成从左上到左下，每一步只能 ↓↘↙，求所有可能的路径数量\n\"\"\"\n\n\ndef find_unique_paths(m, n):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :rtype: int\n\n    >>> gotcha = [\n    ...     find_unique_paths(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 2), 1), ((2, 3), 2), ((3, 3), 2),\n    ...         ((5, 5), 9), ((7, 6), 21), ((6, 7), 51),\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    if not m or not n:\n        return 0\n\n    dp = [[0] * n for _ in range(m)]\n    dp[0][0] = 1\n\n    for y in range(1, n):\n        for x in range(m):\n            dp[x][y] = dp[x][y - 1]\n\n            if x > 0:\n                dp[x][y] += dp[x - 1][y - 1]\n\n            if x + 1 < m:\n                dp[x][y] += dp[x + 1][y - 1]\n\n    return dp[0][n - 1]\n\n\ndef find_unique_paths1(m, n):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :rtype: int\n\n    >>> gotcha = [\n    ...     find_unique_paths1(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 2), 1), ((2, 3), 2), ((3, 3), 2),\n    ...         ((5, 5), 9), ((7, 6), 21), ((6, 7), 51),\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    if not m or not n:\n        return 0\n\n    dp = [0] * m\n    dp[0] = 1\n    pre = cur = 0\n\n    for y in range(1, n):\n        pre = cur = 0\n\n        for x in range(m):\n            pre, cur = cur, dp[x]\n\n            if x > 0:\n                dp[x] += pre\n\n            if x + 1 < m:\n                dp[x] += dp[x + 1]\n\n    return dp[0]\n\n\ndef find_unique_paths2(m, n, points):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :type points: list[list[int]]\n    :rtype: bool\n\n    >>> gotcha = [\n    ...     find_unique_paths2(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 3, [[1, 0], [1, 1], [1, 2]]), False),\n    ...         ((3, 3, [[1, 0], [2, 1], [1, 2]]), False),\n    ...         ((3, 3, [[1, 0], [1, 1], [1, 2]]), False),\n    ...         ((5, 5, [[0, 1], [2, 2], [1, 3]]), False),\n    ...         ((5, 5, [[1, 1], [2, 2], [1, 3]]), True),\n    ...         ((5, 5, [[2, 2], [1, 1], [1, 3]]), True),\n    ...         ((6, 8, [[0, 0], [4, 3], [0, 7]]), False),\n    ...         ((8, 6, [[1, 1], [0, 4], [1, 3]]), True),\n    ...         ((8, 6, [[1, 1], [0, 4], [2, 3]]), False),\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    if not m or not n or not points or len(points) < 3:\n        return False\n\n    path = [(0, 0), (0, n - 1)]\n    path.extend(tuple(p) for p in points)\n    path.sort(key=lambda p: (p[1], p[0]))\n\n    for i in range(1, len(path)):\n        x, y = path[i]\n        _x, _y = path[i - 1]\n        delta = y - _y\n\n        if not (x - delta <= _x <= x + delta):\n            return False\n\n    return True\n\n\ndef find_unique_paths3(m, n, points):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :type points: list[list[int]]\n    :rtype: int\n\n    >>> gotcha = [\n    ...     find_unique_paths3(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 3, [[1, 0], [1, 1], [1, 2]]), 0),\n    ...         ((3, 3, [[1, 0], [2, 1], [1, 2]]), 0),\n    ...         ((3, 3, [[1, 0], [1, 1], [1, 2]]), 0),\n    ...         ((5, 5, [[0, 1], [2, 2], [1, 3]]), 0),\n    ...         ((5, 5, [[1, 1], [2, 2], [1, 3]]), 1),\n    ...         ((5, 5, [[2, 2], [1, 1], [1, 3]]), 1),\n    ...         ((6, 8, [[0, 0], [4, 3], [0, 7]]), 0),\n    ...         ((8, 6, [[0, 0], [0, 5], [0, 4]]), 9),\n    ...         ((8, 6, [[1, 1], [0, 4], [2, 3]]), 0),\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    NOT_FOUND = 0\n\n    if not m or not n or not points:\n        return NOT_FOUND\n\n    points.sort(key=lambda p: (p[1], p[0]))\n\n    dp = [[0] * n for _ in range(m)]\n    dp[0][0] = 1\n    k = len(points)\n    i = 0\n\n    while points[i][1] == 0:\n        i += 1\n\n    if i >= k:\n        return NOT_FOUND\n\n    for y in range(1, n):\n        for x in range(m):\n            dp[x][y] = dp[x][y - 1]\n\n            if x > 0:\n                dp[x][y] += dp[x - 1][y - 1]\n\n            if x + 1 < m:\n                dp[x][y] += dp[x + 1][y - 1]\n\n        if i < k and y == points[i][1]:\n            for x in range(m):\n                if x != points[i][0]:\n                    dp[x][y] = 0\n            i += 1\n\n    return dp[0][n - 1] if i == k else NOT_FOUND\n\n\ndef find_unique_paths4(m, n, h):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :type h: int\n    :rtype: int\n\n    >>> gotcha = [\n    ...     find_unique_paths4(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 3, 1), 1), ((3, 3, 1), 1), ((3, 3, 2), 0),\n    ...         ((4, 4, 0), 4), ((4, 4, 1), 3), ((4, 4, 2), 0),\n    ...         ((6, 7, 0), 51), ((6, 7, 1), 50), ((6, 7, 2), 19),\n    ...         ((6, 7, 3), 1), ((6, 7, 4), 0), ((6, 7, 5), 0)\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    if not m or not n:\n        return 0\n\n    dp = [[0] * n for _ in range(m)]\n    dp[0][0] = 1\n\n    for y in range(1, n):\n        for x in range(m):\n            dp[x][y] = dp[x][y - 1]\n\n            if x > 0:\n                dp[x][y] += dp[x - 1][y - 1]\n\n            if x + 1 < m:\n                dp[x][y] += dp[x + 1][y - 1]\n\n    if h < 1:\n        return dp[0][n - 1]\n\n    for y in range(n):\n        for x in range(h):\n            dp[x][y] = 0\n\n    for y in range(1, n):\n        for x in range(h - 1, -1, -1):\n            dp[x][y] = dp[x][y - 1]\n\n            if x > 0:\n                dp[x][y] += dp[x - 1][y - 1]\n\n            if x + 1 < m:\n                dp[x][y] += dp[x + 1][y - 1]\n\n    return dp[0][n - 1]\n\n\ndef find_unique_paths5(m, n):\n    \"\"\"\n    :type m: int\n    :type n: int\n    :rtype: int\n\n    >>> gotcha = [\n    ...     find_unique_paths5(*_in) == _out\n    ...     for _in, _out in (\n    ...         ((2, 2), 1), ((2, 3), 1), ((3, 3), 2),\n    ...         ((5, 5), 9), ((7, 6), 51), ((6, 7), 21),\n    ...     )\n    ... ]\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    if not m or not n:\n        return 0\n\n    dp = [[0] * n for _ in range(m)]\n    dp[0][0] = 1\n\n    for x in range(1, m):\n        for y in range(n):\n            dp[x][y] = dp[x - 1][y]\n\n            if y > 0:\n                dp[x][y] += dp[x - 1][y - 1]\n\n            if y + 1 < n:\n                dp[x][y] += dp[x - 1][y + 1]\n\n    return dp[m - 1][0]\n"
  },
  {
    "path": "other/unique_word_abbreviation_ii.py",
    "content": "\"\"\"\nThis question is the follow-up of `leetcode/288_unique_word_abbreviation`\n\n1. test `WordIterator`\n>>> gotcha = []\n>>> for _in, _out in (\n...     ('', []),\n...     ('a', ['a']),\n...     ('dog', ['3', 'd2', '2g', 'dog']),\n...     ('abcd', ['4', 'a3', '3d', 'ab2', 'a2d', '2cd', 'abcd']),\n...     ('price', ['5', 'p4', '4e', 'pr3', 'p3e', '3ce', 'pri2', 'pr2e', 'p2ce', '2ice', 'price']),\n... ):\n...     res = [w for w in WordIterator(_in)]\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\n2. test `find_unique_abbreviations`\n>>> gotcha = []\n>>> for _in, _out in (\n...     (\n...         ['internationalization', 'localization', 'dog', 'accessibility', 'automatically'],\n...         ['20', '12', '3', 'ac11', 'au11']\n...     ),\n...     (\n...         ['aaabcdefg', 'aaabbcdef', 'aaabbbcde'],\n...         ['8g', '8f', '8e'],\n...     ),\n...     (\n...         ['abcdef', 'abcdef', 'abcdef'],\n...         ['6', '6', '6'],\n...     ),\n...     (\n...         ['abcdef', 'abdeef', 'abefef'],\n...         ['abc3', 'abd3', 'abe3'],\n...     ),\n... ):\n...     res = find_unique_abbreviations(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef find_unique_abbreviations(words):\n    iterators = {}  # {abbr: iterator}\n\n    for word in set(words):\n        iterator = (WordIterator(word).__iter__(), word)\n        abbr = next(iterator[0], None)\n\n        if not abbr:\n            continue\n\n        if abbr in iterators:\n            iterators[abbr].append(iterator)\n        else:\n            iterators[abbr] = [iterator]\n\n    collisions = [key for key, iters in iterators.items() if len(iters) > 1]\n\n    while collisions:\n        for key in collisions:\n            iters = iterators[key]\n            del iterators[key]\n\n            for iterator in iters:\n                abbr = next(iterator[0], None)\n\n                if not abbr:\n                    continue\n\n                if abbr in iterators:\n                    iterators[abbr].append(iterator)\n                else:\n                    iterators[abbr] = [iterator]\n\n        collisions = [key for key, iters in iterators.items() if len(iters) > 1]\n\n    reversed_index = {iters[0][1]: key for key, iters in iterators.items() if len(iters) == 1}\n\n    return [reversed_index[word] for word in words]\n\n\nclass WordIterator:\n    def __init__(self, word):\n        self.word = word\n        self.TMPL = '{}{}{}'\n\n    def __iter__(self):\n        if not self.word:\n            return\n\n        n = len(self.word)\n\n        if n > 1:\n            yield str(n)\n\n        for i in range(1, n - 1):\n            for j in range(i + 1):\n                yield self.TMPL.format(\n                    self.word[:i - j],\n                    n - i,\n                    self.word[-j:] if j > 0 else ''\n                )\n\n        yield self.word\n"
  },
  {
    "path": "other/upside_down_numbers.py",
    "content": "def find_upside_down_numbers(n):\n    \"\"\"\n    :type n: int\n    :rtype: list[int]\n\n    >>> gotcha = []\n    >>> for _in, _out in (\n    ...     (10, [1, 6, 8, 9]),\n    ...     (100, [1, 6, 8, 9, 16, 18, 19, 61, 66, 68, 81, 86, 89, 91, 98, 99]),\n    ...     (500, [1, 6, 8, 9, 16, 18, 19, 61, 66, 68, 81, 86, 89, 91, 98, 99, 161, 191]),\n    ...     (700, [1, 6, 8, 9, 16, 18, 19, 61, 66, 68, 81, 86, 89, 91, 98, 99, 161, 169, 189, 191, 199, 611, 661, 669, 681]),\n    ... ):\n    ...     res = find_upside_down_numbers(_in)\n    ...     if res != _out: print(_in, res)\n    ...     gotcha.append(res == _out)\n    >>> bool(gotcha) and all(gotcha)\n    True\n    \"\"\"\n    ans = []\n\n    if not n or n <= 0:\n        return ans\n\n    cands = '01689'\n    queue, _queue = ['1', '6', '8', '9'], []\n    up_down_nums = {\n        '0': '0',\n        '1': '1',\n        '6': '9',\n        '8': '8',\n        '9': '6',\n    }\n\n    while queue:\n        ans.extend(queue)\n\n        for num in queue:\n            for nxt in cands:\n                res = num + nxt\n                rev = get_reversed_number(res, up_down_nums)\n\n                if rev[0] == '0' or res == rev or int(rev) > n:\n                    continue\n\n                if int(res) > n:\n                    ans.extend(_queue)\n                    return [int(s) for s in ans]\n\n                _queue.append(res)\n\n        queue, _queue = _queue, []\n\n    return [int(s) for s in ans]\n\n\ndef get_reversed_number(s, up_down_nums):\n    res = ''\n\n    for i in range(len(s) - 1, -1, -1):\n        res += up_down_nums[s[i]]\n\n    return res\n"
  },
  {
    "path": "pramp/array_index_and_element_equality.py",
    "content": "def index_equals_value_search(nums):\n    if not nums:\n        return -1\n\n    left, right = 0, len(nums) - 1\n\n    while left + 1 < right:\n        mid = (left + right) // 2\n        if nums[left] == left:  # lowest index\n            return left\n        if nums[mid] == mid:\n            return mid\n        if nums[mid] < mid:\n            left = mid\n        else:\n            right = mid\n\n    for mid in (left, right):\n        if nums[mid] == mid:\n            return mid\n\n    return -1\n"
  },
  {
    "path": "pramp/array_of_array_products.py",
    "content": "\"\"\"\nthought:\n=> nums = [a, b, c, d]\n1. fill `ans` with `1`\n=> ans = [1, 1, 1, 1]\n2. scan from left to right, and do multiply continuously\n=> ans = [1, a, a * b, a * b * c]\n3. scan from right to left, and do multiply continuously but with a temp var\n=> prod = b * c * d,  c * d,  d\n=> ans = [b * c * d, a * c * d, a * b * d, a * b * c]\n\"\"\"\n\n\ndef array_of_array_products(nums):\n    \"\"\"\n    :type nums: list[int]\n    :rtype: list[int]\n    \"\"\"\n    if not nums or len(nums) <= 1:\n        return []\n\n    n = len(nums)\n    ans = [1] * n\n\n    # 1st scan [1, a, a * b, a * b * c]\n    for i in range(1, n):\n        ans[i] *= ans[i - 1] * nums[i - 1]\n\n    # 2nd scan\n    prod = 1\n    for i in range(n - 2, -1, -1):\n        prod *= nums[i + 1]\n        ans[i] *= prod\n\n    return ans\n"
  },
  {
    "path": "pramp/award_budget_cuts.py",
    "content": "\"\"\"\nMain Concept:\n\nbudget = 190\n[2, 100, 35, 120, 1000]\n=> sort, [1000, 120, 100, 35, 2]\n=> total = sum(arr) - budget\n=> just treat it as bar chart\n   and iterate from start to end to remove the area between `a` and `b`\n   from total below\n   |-|    -> a\n   |=|=|  -> b\n   | | |-|\n=> untill total < 0 => reach the `cap` line\n=> remove the remaining area from total\n\n\n>>> EPS = 1 ** -3\n>>> gotcha = []\n>>> for _in, _out in (\n...     (([2, 4], 3), 1.5),\n...     (([2, 4, 6], 3), 1.0),\n...     (([2, 100, 50, 120, 167], 400), 128.0),\n...     (([2, 100, 50, 120, 1000], 190), 47.0),\n...     (([2, 100, 35, 120, 1000], 190), 51.0),\n...     (([21, 100, 50, 120, 130, 110], 140), 23.8),\n...     (([210, 200, 150, 193, 130, 110, 209, 342, 117], 1530), 211.0),\n... ):\n...     res = find_grants_cap(*_in)\n...     if abs(res - _out) >= EPS: print(_in, res)\n...     gotcha.append(abs(res - _out) < EPS)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef find_grants_cap(grantsArray, newBudget):\n    \"\"\"\n    :type grantsArray: list[int]\n    :type newBudget: int\n    :rtype: float\n    \"\"\"\n    n = len(grantsArray)\n    area = sum(grantsArray) - newBudget\n\n    grantsArray.sort(reverse=True)\n\n    i = segment_sum = 0\n\n    while i < n:\n        if i == n - 1:\n            # (i + 1) * (grantsArray[i] - 0)\n            segment_sum = n * grantsArray[i]\n        else:\n            segment_sum = (i + 1) * (grantsArray[i] - grantsArray[i + 1])\n\n        if area < segment_sum:\n            break\n\n        area -= segment_sum\n        i += 1\n\n    return grantsArray[i] - area / float(i + 1)\n"
  },
  {
    "path": "pramp/bracket_match.py",
    "content": "def bracket_match(text):\n    ans = 0\n    if not text:\n        return ans\n\n    cnt = 0\n\n    for c in text:\n        if c == '(':\n            cnt += 1\n        elif c == ')':\n            cnt -= 1\n\n        if cnt < 0:\n            cnt = 0\n            ans += 1\n\n    if cnt > 0:\n        ans += cnt\n\n    return ans\n"
  },
  {
    "path": "pramp/busiest_time_in_the_mall.py",
    "content": "def find_busiest_period(data):\n    timestamp = -1\n\n    if not data:\n        return timestamp\n    if len(data) == 1: # data[0][2] always 1\n        return data[0][0]\n\n    n = len(data)\n    cnt = maxi = 0\n\n    for i in range(len(data)):\n        if data[i][2] == 1:\n            cnt += data[i][1]\n        else:\n            cnt -= data[i][1]\n\n        if (i == n - 1 or data[i][0] != data[i + 1][0]) and cnt > maxi:\n            maxi = cnt\n            timestamp = data[i][0]\n\n    return timestamp\n"
  },
  {
    "path": "pramp/decrypt_message.py",
    "content": "\"\"\"\nEncryption Rules:\n1. add 1 to the ascii of first letter\n2. add the ascii of prev letter, form second to last\n3. keep substract 26 from every letter until it is in [ord('a'), ord('z')]\n\nTesting:\n>>> gotcha = []\n>>> for origin, encryption in (\n...     ('crime', 'dnotq'),\n...     ('encyclopedia', 'flgxswdliefy'),\n...     ('qqqqq', 'rajsb'),\n...     ('abcdefghijklmnopqrstuvwxyz', 'bvqmjhgghjmqvbiqzjugthwmdv'),\n...     ('drugtrafficking', 'eobamwpnlmhklrq'),\n...     ('', ''),\n... ):\n...     res = encrypt(origin)\n...     if res != encryption: print('L18', origin, res)\n...     gotcha.append(res == encryption)\n...\n...     res = decrypt(encryption)\n...     if res != origin: print('L22', encryption, res)\n...     gotcha.append(res == origin)\n...\n...     res = decrypt(encrypt(origin))\n...     if res != origin: print('L26', origin, res)\n...     gotcha.append(res == origin)\n...\n...     res = decrypt2(encryption)\n...     if res != origin: print('L30', encryption, res)\n...     gotcha.append(res == origin)\n...\n...     res = decrypt2(encrypt(origin))\n...     if res != origin: print('L34', origin, res)\n...     gotcha.append(res == origin)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef encrypt(word):\n    if not word:\n        return ''\n\n    a = ord('a')\n    ans = [ord(c) for c in word]\n    cumul = 1\n\n    for i in range(len(word)):\n        cumul += ans[i]\n        ans[i] = chr((cumul - a) % 26 + a)\n\n    return ''.join(ans)\n\n\ndef decrypt(word):\n    if not word:\n        return ''\n\n    a = ord('a')\n    ans = [ord(c) for c in word]\n\n    for i in range(len(word) - 1, -1, -1):\n        if i == 0:\n            ans[i] = chr((ans[i] - 1 - a) % 26 + a)\n        else:\n            ans[i] = chr((ans[i] - ans[i - 1] - a) % 26 + a)\n\n    return ''.join(ans)\n\n\ndef decrypt2(word):\n    if not word:\n        return ''\n\n    a = ord('a')\n    ans = [ord(c) for c in word]\n    cumul = 1\n\n    for i in range(len(word)):\n        # substract the cumul sum\n        ans[i] -= cumul\n\n        # keep adding 26 to make ans[i] in [ord('a'), ord('z')]\n        steps = (a - ans[i]) // 26\n        if (a - ans[i]) % 26:\n            # (a - ans[i]) % 26 != 0\n            # add 1 more\n            steps += 1\n        ans[i] += steps * 26\n\n        # update cumul\n        cumul += ans[i]\n        ans[i] = chr(ans[i])\n\n    return ''.join(ans)\n"
  },
  {
    "path": "pramp/deletion_distance.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for _in, _out in (\n...     (('', ''), 0), (('', 'hit'), 3), (('neat', ''), 4),\n...     (('heat', 'hit'), 3), (('hot', 'not'), 2), (('some', 'thing'), 9),\n...     (('abc', 'adbc'), 1), (('awesome', 'awesome'), 0), (('ab', 'ba'), 2),\n... ):\n...     for get_distance in (deletion_distance, deletion_distance2):\n...         res = get_distance(*_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef deletion_distance(s, t):\n    if s == t:\n        return 0\n    if not s and not t:\n        return 0\n    if not s:\n        return len(t)\n    if not t:\n        return len(s)\n\n    m, n = len(s), len(t)\n    dp = [[0] * (n + 1) for _ in range(m + 1)]\n\n    for i in range(1, m + 1):\n        dp[i][0] = i\n    for j in range(1, n + 1):\n        dp[0][j] = j\n\n    for i in range(1, m + 1):\n        for j in range(1, n + 1):\n            if s[i - 1] == t[j - 1]:\n                dp[i][j] = dp[i - 1][j - 1]\n            else:\n                dp[i][j] = 1 + min(\n                    dp[i - 1][j],\n                    dp[i][j - 1]\n                )\n\n    return dp[m][n]\n\n\ndef deletion_distance2(s, t):\n    if s == t:\n        return 0\n    if not s and not t:\n        return 0\n    if not s:\n        return len(t)\n    if not t:\n        return len(s)\n\n    m, n = len(s), len(t)\n    dp = [[0] * (n + 1) for _ in range(2)]\n    pre = cur = 0\n\n    for j in range(1, n + 1):\n        dp[cur][j] = j\n\n    for i in range(1, m + 1):\n        pre, cur = cur, 1 - cur\n        dp[cur][0] = i\n\n        for j in range(1, n + 1):\n            if s[i - 1] == t[j - 1]:\n                dp[cur][j] = dp[pre][j - 1]\n            else:\n                dp[cur][j] = 1 + min(\n                    dp[pre][j],\n                    dp[cur][j - 1]\n                )\n\n    return dp[cur][n]\n"
  },
  {
    "path": "pramp/drone_flight_planner.py",
    "content": "def calc_drone_min_energy(route):\n    ans = 0\n\n    if not route or len(route) < 2:\n        return ans\n\n    delta = 0\n    max_z = route[0][2]\n\n    for i in range(1, len(route)):\n        delta += route[i][2] - route[i - 1][2]\n\n        if route[i][2] > max_z:\n            max_z = route[i][2]\n            ans = delta\n\n    return ans\n"
  },
  {
    "path": "pramp/find_the_duplicates.py",
    "content": "def find_duplicates(arr1, arr2):\n    ans = []\n\n    if not arr1 or not arr2:\n        return ans\n\n    m, n = len(arr1), len(arr2)\n    i = j = 0\n\n    while i < m and j < n:\n        if arr1[i] < arr2[j]:\n            i += 1\n        elif arr1[i] > arr2[j]:\n            j += 1\n        else:\n            if not ans or arr1[i] != ans[-1]:\n                ans.append(arr1[i])\n            i += 1\n            j += 1\n\n    return ans\n\n\ndef find_duplicates2(arr1, arr2):\n    ans = []\n\n    if not arr1 or not arr2:\n        return ans\n\n    vals = {}\n\n    for num in arr1:\n        vals[num] = False\n\n    for num in arr2:\n        if num in vals and vals[num] is False:\n            vals[num] = True\n            ans.append(num)\n\n    return ans\n\n\ndef find_duplicates3(arr1, arr2):\n    if not arr1 or not arr2:\n        return []\n\n    val1 = set(arr1)\n    val2 = set(arr2)\n\n    return list(val1 & val2)\n\n\nif __name__ == '__main__':\n    print(find_duplicates([1, 2, 3, 5, 6, 7], [3, 6, 7, 8, 20]))\n    print(find_duplicates([1, 2, 3, 3, 5, 6, 7], [3, 3, 6, 7, 8, 20]))\n    print(find_duplicates2([1, 2, 3, 5, 6, 7], [3, 6, 7, 8, 20]))\n    print(find_duplicates2([1, 2, 3, 3, 5, 6, 7], [3, 3, 6, 7, 8, 20]))\n    print(find_duplicates3([1, 2, 3, 5, 6, 7], [3, 6, 7, 8, 20]))\n    print(find_duplicates3([1, 2, 3, 3, 5, 6, 7], [3, 3, 6, 7, 8, 20]))\n"
  },
  {
    "path": "pramp/flatten_a_dictionary.py",
    "content": "def flatten_dictionary(dictionary):\n    ans = {}\n\n    if not dictionary:\n        return ans\n\n    dfs(dictionary, [], ans)\n    return ans\n\n\ndef dfs(dictionary, keys, ans):\n    if not isinstance(dictionary, dict):\n        key = '.'.join(keys)\n        ans[key] = dictionary\n        return\n\n    for key in dictionary:\n        if key:\n            keys.append(key)\n\n        dfs(dictionary[key], keys, ans)\n\n        if key:\n            keys.pop()\n"
  },
  {
    "path": "pramp/h_tree_construction.py",
    "content": "def draw_line(x1, y1, x2, y2):\n    pass\n\n\ndef draw_h_tree(x, y, length, depth):\n    \"\"\"iteration\n    :type x: float\n    :type y: float\n    :type length: float\n    :type depth: float\n    :rtype: void\n    \"\"\"\n    queue, _queue = [(x, y)], []\n\n    for _ in range(depth):\n        for x, y in queue:\n            x1 = x - length / 2\n            y1 = y + length / 2\n            x2 = x + length / 2\n            y2 = y - length / 2\n\n            draw_line(x1, y1, x1, y2)\n            draw_line(x2, y1, x2, y2)\n            draw_line(x1, y, x2, y)\n\n            _queue.append((x1, y1))\n            _queue.append((x1, y2))\n            _queue.append((x2, y1))\n            _queue.append((x2, y2))\n\n        queue, _queue = _queue, []\n        length /= 2 ** 0.5\n\n\ndef draw_h_tree2(x, y, length, depth):\n    \"\"\"recursion\n    :type x: float\n    :type y: float\n    :type length: float\n    :type depth: float\n    :rtype: void\n    \"\"\"\n    if depth == 0:\n        return\n\n    x1 = x - length / 2\n    y1 = y + length / 2\n    x2 = x + length / 2\n    y2 = y - length / 2\n\n    draw_line(x1, y1, x1, y2)\n    draw_line(x2, y1, x2, y2)\n    draw_line(x1, y, x2, y)\n\n    _length = length / (2 ** 0.5)\n    _depth = depth - 1\n\n    draw_h_tree2(x1, y1, _length, _depth)\n    draw_h_tree2(x1, y2, _length, _depth)\n    draw_h_tree2(x2, y1, _length, _depth)\n    draw_h_tree2(x2, y2, _length, _depth)\n"
  },
  {
    "path": "pramp/k_messed_array_sort.py",
    "content": "import heapq\n\n\ndef sort_k_messed_array(nums, k):\n    \"\"\"\n    Given an array of integers arr where each element is at most k places away from its sorted position.\n\n    time: O(n * log(k))\n    space: O(k)\n    \"\"\"\n    if not nums or not k:\n        return nums\n\n    n = len(nums)\n    heap = []\n\n    for i in range(k + 1):\n        heapq.heappush(heap, nums[i])\n\n    for i in range(k + 1, n):\n        nums[i - k - 1] = heapq.heappop(heap)\n        heapq.heappush(heap, nums[i])\n\n    for i in range(n - k - 1, n):\n        nums[i] = heapq.heappop(heap)\n\n    return nums\n"
  },
  {
    "path": "pramp/largest_smaller_bst_node.py",
    "content": "def largest_smaller_bst_node(root, target):\n    ans = -1\n\n    if not root:\n        return ans\n\n    while root:\n        if root.val < target:\n            ans = root.val\n            root = root.right\n        else:\n            root = root.left\n\n    return ans\n"
  },
  {
    "path": "pramp/number_of_paths.py",
    "content": "def num_of_paths_to_dest(n):\n    if not n or n == 0:\n        return 0\n    if n == 1:\n        return 1\n\n    dp = [[0] * n for _ in range(n)]\n\n    for i in range(n):\n        dp[i][0] = 1\n\n    for i in range(1, n):\n        for j in range(1, i + 1):\n            dp[i][j] = dp[i - 1][j] + dp[i][j - 1]\n\n    return dp[n - 1][n - 1]\n"
  },
  {
    "path": "pramp/pairs_with_specific_difference.py",
    "content": "def find_pairs_with_given_difference(arr, k):\n    ans = []\n\n    if not arr or not isinstance(k, int):\n        return ans\n\n    n = len(arr)\n    sums = {}\n\n    for i in range(n):\n        sums[arr[i] - k] = i\n\n    for j in range(n):\n        if arr[j] in sums:\n            i = sums[arr[j]]\n            ans.append([arr[i], arr[j]])\n\n    return ans\n"
  },
  {
    "path": "pramp/pancake_sort.py",
    "content": "\"\"\"\nMain Concept:\n1. find the max and do `flip` in [0,max_idx]\n2. the max is already at `0`, `flip` it to the correct pos\n3. repeat (1)\n\n   [1,5,2,4,3]\n=> [5,1,2,4,3]\n=> [3,4,2,1,5]\n=> [4,3,2,1,5]\n=> [1,2,3,4,5]\n\nTesting:\n>>> gotcha = []\n>>> for _in, _out in (\n...     (([1, 2, 3, 4, 5], 3), [3, 2, 1, 4, 5]),\n...     (([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]),\n...     (([1, 2, 3, 4, 5], 5), [5, 4, 3, 2, 1]),\n...     (([1, 2, 3, 4, 5], 6), [5, 4, 3, 2, 1]),\n... ):\n...     flip(*_in)\n...     if _in[0] != _out: print(_in, _out)\n...     gotcha.append(_in[0] == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n>>> gotcha = []\n>>> for _in, _out in (\n...     ([1, 5, 4, 3, 2], [1, 2, 3, 4, 5]),\n...     ([5, 1, 3, 4, 2], [1, 2, 3, 4, 5]),\n...     ([1, 4, 2, 3, 5], [1, 2, 3, 4, 5]),\n...     ([5, 10, 1, 20, 4], [1, 4, 5, 10, 20]),\n...     ([5, 1, 4, 20, 10], [1, 4, 5, 10, 20]),\n... ):\n...     res = pancake_sort(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef pancake_sort(nums):\n    \"\"\"using `flip` to sort input in order\n    :type nums: list[int]\n    :rtype: list[int]\n    \"\"\"\n    for j in range(len(nums) - 1, -1, -1):\n        i = get_max_index(nums, j)\n        flip(nums, i + 1)\n        flip(nums, j + 1)\n\n    return nums\n\n\ndef flip(nums, k):\n    \"\"\"reverses the order of the first `k` elements in the array `nums` place\n    :type nums: list[int]\n    :type k: int\n    :rtype: void\n    \"\"\"\n    if not nums:\n        return\n\n    if not k or k <= 1:\n        return\n\n    k = min(k, len(nums))\n    i, j = 0, k - 1\n\n    while i < j:\n        nums[i], nums[j] = nums[j], nums[i]\n        i += 1\n        j -= 1\n\n\ndef get_max_index(nums, i):\n    \"\"\"return the index of the maximum in [0,i] of `nums`\n    :type nums: list[int]\n    :type i: int\n    :rtype: int\n    \"\"\"\n    k = 0\n\n    for j in range(1, i + 1):\n        if nums[j] > nums[k]:\n            k = j\n\n    return k\n"
  },
  {
    "path": "pramp/root_of_number.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for _in, _out in (\n...     ((4, 2), 2),\n...     ((9, 3), 2.08),\n...     ((7, 3), 1.913),\n...     ((11, 4), 1.821),\n... ):\n...     res = root(*_in)\n...     valid = abs(res - _out) < 0.001\n...     if not valid: print(_in, res)\n...     gotcha.append(valid)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef root(x, n):\n    if not x or x in (0, 1):\n        return x\n\n    left = 0\n    right = max(1, x)\n\n    while right - left > 1e-4:\n        mid = (left + right) / 2.0\n        product = get_product(mid, n)\n\n        if product < x:\n            left = mid\n        elif product > x:\n            right = mid\n        else:\n            return mid\n\n    return (left + right) / 2.0\n\n\ndef get_product(x, n):\n    res = 1\n\n    for _ in range(n):\n        res *= x\n\n    return res\n"
  },
  {
    "path": "pramp/sales_path.py",
    "content": "\"\"\"\n1. find the minimum cost for the path from root through leaf\n   => get_cheapest_cost\n2. find all paths which have the minimum cost\n   => get_cheapest_cost_paths\n   => how to find all paths by one-pass?\n\nNode Structure:\n>>> class TreeNode:\n...     def __init__(self, cost):\n...         self.cost = cost\n...         self.children = []\n\nTesting:\n>>> trees = []\n>>> TEST_CASE = (\n...     ((\n...         (0, 0, [1, 2, 3]),\n...         (1, 5, [4]),\n...         (2, 3, [5]),\n...         (3, 6, [6]),\n...         (4, 4, []),\n...         (5, 2, []),\n...         (6, 1, []),\n...     ), 5, [[0, 3, 2]]),\n...     ((\n...         (0, 0, [1, 2, 3]),\n...         (1, 5, [4]),\n...         (2, 3, [5, 6]),\n...         (3, 6, [7, 8]),\n...         (4, 4, []),\n...         (5, 2, [9]),\n...         (6, 0, [10]),\n...         (7, 1, []),\n...         (8, 5, []),\n...         (9, 1, [11]),\n...         (10, 10, []),\n...         (11, 1, []),\n...     ), 7, [[0, 3, 2, 1, 1], [0, 6, 1]]),\n... )\n>>> for case, _, _ in TEST_CASE:\n...     nodes = {}\n...     for id, cost, _ in case:\n...         nodes[id] = TreeNode(cost)\n...     for id, _, children in case:\n...         nodes[id].children = [nodes[id] for id in children]\n...     trees.append(nodes[0])\n\n1. test get_cheapest_cost:\n>>> gotcha = []\n>>> for i in range(len(TEST_CASE)):\n...     res = get_cheapest_cost(trees[i])\n...     if res != TEST_CASE[i][1]: print(i, res)\n...     gotcha.append(res == TEST_CASE[i][1])\n>>> bool(gotcha) and all(gotcha)\nTrue\n\n2. test get_cheapest_cost_paths:\n>>> gotcha = []\n>>> for i in range(len(TEST_CASE)):\n...     res = get_cheapest_cost_paths(trees[i])\n...     if res != TEST_CASE[i][2]: print(i, res)\n...     gotcha.append(res == TEST_CASE[i][2])\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef get_cheapest_cost(root):\n    if not root:\n        return 0\n    if not root.children:\n        return root.cost\n\n    res = float('inf')\n\n    for child in root.children:\n        tmp = get_cheapest_cost(child)\n\n        if tmp < res:\n            res = tmp\n\n    return res + root.cost\n\n\ndef get_cheapest_cost_paths(root):\n    ans = []\n\n    if not root:\n        return ans\n\n    min_val = get_cheapest_cost(root)\n    _dfs(root, min_val, ans, [root.cost])\n\n    return ans\n\n\ndef _dfs(root, target, ans, path):\n    if not root:\n        return\n    if not root.children and target == 0:\n        ans.append(path[:])\n        return\n    if not root.children:\n        return\n\n    for child in root.children:\n        if target < child.cost:\n            continue\n\n        path.append(child.cost)\n        _dfs(child, target - child.cost, ans, path)\n        path.pop()\n"
  },
  {
    "path": "pramp/sentence_reverse.py",
    "content": "\"\"\"\nTest Case:\n\n>>> gotcha = []\n>>> for _in, _out in (\n...     ([' ', ' '], [' ', ' ']),\n...     (['a', ' ', ' ', 'b'], ['b', ' ', ' ', 'a']),\n...     (['h', 'e', 'l', 'l', 'o'], ['h', 'e', 'l', 'l', 'o']),\n...     (\n...         ['p', 'e', 'r', 'f', 'e', 'c', 't', ' ', 'm', 'a', 'k', 'e', 's', ' ', 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e'],\n...         ['p', 'r', 'a', 'c', 't', 'i', 'c', 'e', ' ', 'm', 'a', 'k', 'e', 's', ' ', 'p', 'e', 'r', 'f', 'e', 'c', 't']\n...     ),\n...     (\n...         ['y', 'o', 'u', ' ', 'w', 'i', 't', 'h', ' ', 'b', 'e', ' ', 'f', 'o', 'r', 'c', 'e', ' ', 't', 'h', 'e', ' ', 'm', 'a', 'y'],\n...         ['m', 'a', 'y', ' ', 't', 'h', 'e', ' ', 'f', 'o', 'r', 'c', 'e', ' ', 'b', 'e', ' ', 'w', 'i', 't', 'h', ' ', 'y', 'o', 'u']\n...     ),\n...     (\n...         ['g', 'r', 'e', 'a', 't', 'e', 's', 't', ' ', 'n', 'a', 'm', 'e', ' ', 'f', 'i', 'r', 's', 't', ' ', 'e', 'v', 'e', 'r', ' ', 'n', 'a', 'm', 'e', ' ', 'l', 'a', 's', 't'],\n...         ['l', 'a', 's', 't', ' ', 'n', 'a', 'm', 'e', ' ', 'e', 'v', 'e', 'r', ' ', 'f', 'i', 'r', 's', 't', ' ', 'n', 'a', 'm', 'e', ' ', 'g', 'r', 'e', 'a', 't', 'e', 's', 't']\n...     ),\n...     ([' ', ' ', 'a', ' ', 'b', 'c'], ['b', 'c', ' ', 'a', ' ', ' ']),\n...     (['b', 'c', ' ', 'a', ' ', ' '], [' ', ' ', 'a', ' ', 'b', 'c']),\n...     ([' ', ' ', 'a', ' ', 'b', 'c', ' '], [' ', 'b', 'c', ' ', 'a', ' ', ' ']),\n... ):\n...     for test_func in (reverse_words, reverse_words2):\n...         res = test_func(_in)\n...         if res != _out: print(_in, res)\n...         gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\n\"\"\"\nApproach 1: use built-in function\n\"\"\"\ndef reverse_words(arr):\n    return list(' '.join(reversed(''.join(arr).split(' '))))\n\n\n\"\"\"\nApproach 2: swap children and modify in place\n\"\"\"\ndef reverse_words2(arr):\n    if not arr:\n        return []\n\n    n = len(arr)\n    reverse_in_range(arr, 0, n - 1)\n\n    left = 0\n\n    while left < n and arr[left] == ' ':\n        left += 1\n\n    for right in range(n):\n        if arr[right] != ' ':\n            continue\n\n        reverse_in_range(arr, left, right - 1)\n        left = right + 1\n\n    right = n - 1\n\n    while right >= 0 and arr[right] == ' ':\n        right -= 1\n\n    reverse_in_range(arr, left, right)\n\n    return arr\n\n\ndef reverse_in_range(arr, i, j):\n    \"\"\"\n    to reverse arr[i:j + 1]\n    \"\"\"\n    while i < j:\n        arr[i], arr[j] = arr[j], arr[i]\n        i += 1\n        j -= 1\n"
  },
  {
    "path": "pramp/smallest_substring_of_all_characters.py",
    "content": "def get_shortest_unique_substring(strs, s):\n    if not strs or not s:\n        return ''\n\n    freq = dict.fromkeys(strs, 0)\n    left = cnt = 0\n    start = 0\n    size = INF = float('inf')\n\n    for right in range(len(s)):\n        if s[right] in freq:\n            if freq[s[right]] == 0:\n                cnt += 1\n            freq[s[right]] += 1\n\n        while cnt == len(freq):\n            if right - left + 1 < size:\n                start = left\n                size = right - left + 1\n\n            if s[left] in freq:\n                freq[s[left]] -= 1\n                if freq[s[left]] == 0:\n                    cnt -= 1\n\n            left += 1\n\n    return s[start:start + size] if size < INF else ''\n"
  },
  {
    "path": "pramp/time_planner.py",
    "content": "def meeting_planner(slots1, slots2, duration):\n    if not slots1 or not slots2 or not duration:\n        return []\n\n    m, n = len(slots1), len(slots2)\n    i = j = 0\n\n    while i < m and j < n:\n        start = max(slots1[i][0], slots2[j][0])\n        end = min(slots1[i][1], slots2[j][1])\n\n        if start + duration <= end:\n            return [start, start + duration]\n\n        if slots1[i][1] < slots2[j][1]:\n            i += 1\n        else:\n            j += 1\n\n    return []\n"
  },
  {
    "path": "pramp/word_count_engine.py",
    "content": "\"\"\"\n>>> gotcha = []\n>>> for _in, _out in (\n...     (\n...         \"Practice makes perfect. you'll only get Perfect by practice. just practice!\",\n...         [['practice', 3], ['perfect', 2], ['makes', 1], ['youll', 1], ['only', 1], ['get', 1], ['by', 1], ['just', 1]],\n...     ),\n...     (\n...         \"Practice makes perfect. just practice! you'll only get Perfect by practice.\",\n...         [['practice', 3], ['perfect', 2], ['makes', 1], ['just', 1], ['youll', 1], ['only', 1], ['get', 1], ['by', 1]],\n...     ),\n...     (\n...         \"Practice makes perfect. you'll only get Perfect by practice. just practice by yourself!\",\n...         [['practice', 3], ['perfect', 2], ['by', 2], ['makes', 1], ['youll', 1], ['only', 1], ['get', 1], ['just', 1], ['yourself', 1]],\n...     ),\n... ):\n...     res = word_count_engine(_in)\n...     if res != _out: print(_in, res)\n...     gotcha.append(res == _out)\n>>> bool(gotcha) and all(gotcha)\nTrue\n\"\"\"\n\n\ndef word_count_engine(document):\n    \"\"\"\n    :type document: str\n    :rtype: list[list[str]]\n\n    count and sort\n    time: O(n logn)\n    \"\"\"\n    ans = []\n    document = document and document.strip()\n\n    if not document:\n        return ans\n\n    document = ''.join(c for c in document if c.isalnum() or c == ' ')\n    word2idx = {}\n\n    for word in document.lower().strip().split():\n        if not word:\n            continue\n\n        if word not in word2idx:\n            ans.append([word, 0])\n            word2idx[word] = len(ans) - 1\n\n        i = word2idx[word]\n        ans[i][1] += 1\n\n    ans.sort(key=lambda x: x[1], reverse=True)\n    return ans\n\n\ndef word_count_engine2(document):\n    \"\"\"\n    :type document: str\n    :rtype: list[list[str]]\n\n    # TODO\n    LRU\n    time: O(n)\n    \"\"\"\n    pass\n"
  },
  {
    "path": "topic/README.md",
    "content": "The time and space complexity of common algorithms and data-structures\n======\n\n- Inspired by [Big-O Algorithm Complexity Cheat Sheet @ericdrowell](http://bigocheatsheet.com)\n- For the complexity representation\n  - 1 param: $\\Theta(avg.)$\n  - 2 params: $\\Theta(avg.)$ / $O(worst)$\n  - 3 params: $\\Omega(best)$ / $\\Theta(avg.)$ / $O(worst)$\n\n## Data Structures\n\n| Name | 结构名 | Space | Access | Search | Insert | Delete | Note |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| [Array](http://en.wikipedia.org/wiki/Array_data_structure) | 数组 | $O(n)$ | $\\Theta(1)$ / $O(1)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | Swap with `a[-1]` => $O(1)$ in insert, delete |\n| [Queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) | 队列 | $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(1)$ / $O(1)$ | $\\Theta(1)$ / $O(1)$ | |\n| [Stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) | 栈 | $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(1)$ / $O(1)$ | $\\Theta(1)$ / $O(1)$ | |\n| [Heap](https://en.wikipedia.org/wiki/Heap_(data_structure)) | 堆 | | | | | | Check it in [Heap](./#heap) Section |\n| [Graph](https://en.wikipedia.org/wiki/Graph_(abstract_data_type)) | 图 | | | | | | Check it in [Graph](./#graph) Section |\n| [Singly-Linked List](https://en.wikipedia.org/wiki/Linked_list#Singly_linked_lists) | 单向链表 | $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(1)$ / $O(1)$ | $\\Theta(1)$ / $O(1)$ | |\n| [Doubly-Linked List](https://en.wikipedia.org/wiki/Doubly_linked_list) | 双向链表 | $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(n)$ / $O(n)$ | $\\Theta(1)$ / $O(1)$ | $\\Theta(1)$ / $O(1)$ | |\n| [Skip List](https://en.wikipedia.org/wiki/Skip_list) | 跳跃表 | $O(n\\log{n})$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | |\n| [Hash Table](https://en.wikipedia.org/wiki/Hash_table) | 哈希表 | $O(n)$ | - | $\\Theta(1)$ / $O(n)$ | $\\Theta(1)$ / $O(n)$ | $\\Theta(1)$ / $O(n)$ | |\n| [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) | 二叉查找树 | $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | |\n| [Cartesian Tree](https://en.wikipedia.org/wiki/Cartesian_tree) | 笛卡尔树 | $O(n)$ | - | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | |\n| [B-Tree](https://en.wikipedia.org/wiki/B-tree) | B 树 | $O(n)$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | |\n| [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) | 红黑树 | $O(n)$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | |\n| [Splay Tree](https://en.wikipedia.org/wiki/Splay_tree) | 伸展树 | $O(n)$ | - | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | |\n| [AVL Tree](https://en.wikipedia.org/wiki/AVL_tree) | AVL 树 | $O(n)$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | |\n| [KD Tree](https://en.wikipedia.org/wiki/K-d_tree) | K 维树 | $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | $\\Theta(\\log{n})$ / $O(n)$ | |\n\n### Heap\n\n| Implementation | 结构名 | Heapify | Access Top | Pop Top | Increase Key | Insert | Delete | Merge |\n| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| Linked List (Sorted) | 链表（已排序） | - | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(n)$ | $\\Theta(n)$ | $\\Theta(1)$ | $\\Theta(m+n)$ |\n| Linked List (Unsorted) | 链表（未排序） | - | $\\Theta(n)$ | $\\Theta(n)$ | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(1)$ |\n| [Binary Heap](https://en.wikipedia.org/wiki/Binary_heap) | 二叉堆 | $O(n)$ | $\\Theta(1)$ | $\\Theta(\\log{n})$ | $\\Theta(\\log{n})$ | $\\Theta(\\log{n})$ | $\\Theta(\\log{n})$ | $\\Theta(m+n)$ |\n| [Binomial Heap](https://en.wikipedia.org/wiki/Binomial_heap) | 二项堆 | - | $\\Theta(1)$ | $\\Theta(\\log{n})$ | $\\Theta(\\log{n})$ | $\\Theta(1)$ | $\\Theta(\\log{n})$ | $\\Theta(\\log{n})$ |\n| [Fibonacci Heap](https://en.wikipedia.org/wiki/Fibonacci_heap) | 斐波那契堆 | - | $\\Theta(1)$ | $\\Theta(\\log{n})$ | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(\\log{n})$ | $\\Theta(1)$ |\n\n### Graph\n\n- Graph with $\\lvert{V}\\rvert$ vertices and $\\lvert{E}\\rvert$ edges\n\n| Vertex / Edge Management | 结构名 | Storage | Add Vertex | Add Edge | Remove Vertex | Remove Edge | Search |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| [Adjacency List](http://reference.wolfram.com/language/ref/AdjacencyList.html) | 邻接表 | $O(\\lvert{V}\\rvert+\\lvert{E}\\rvert)$ | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(\\lvert{V}\\rvert+\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert)$ |\n| [Incidence List](http://reference.wolfram.com/language/ref/IncidenceList.html) | 关联表 | $O(\\lvert{V}\\rvert+\\lvert{E}\\rvert)$ | $\\Theta(1)$ | $\\Theta(1)$ | $\\Theta(\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{E}\\rvert)$ |\n| [Adjacency Matrix](http://reference.wolfram.com/language/ref/AdjacencyMatrix.html) | 邻接矩阵 | $O(\\lvert{V}\\rvert^2)$ | $\\Theta(\\lvert{V}\\rvert^2)$ | $\\Theta(1)$ | $\\Theta(\\lvert{V}\\rvert^2)$ | $\\Theta(1)$ | $\\Theta(1)$ |\n| [Incidence Matrix](http://reference.wolfram.com/language/ref/IncidenceMatrix.html) | 关联矩阵 | $O(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | $\\Theta(\\lvert{E}\\rvert)$ |\n\n## Algorithms\n\n### Sorting Algorithms\n\n| Name | 算法名 | Space | Time | Note |\n| --- | --- | --- | --- | --- |\n| [Quick Sort](https://en.wikipedia.org/wiki/Quicksort) | 快速排序 | $O(\\log{n})$ | $\\Omega(n\\log{n})$ / $\\Theta(n\\log{n})$ / $O(n^2)$ | Basic<br />Unstable |\n| [Merge Sort](https://en.wikipedia.org/wiki/Merge_sort) | 归并排序 | $O(n)$ | $\\Omega(n\\log{n})$ / $\\Theta(n\\log{n})$ / $O(n\\log{n})$ | Basic<br />Stable |\n| [Heap Sort](https://en.wikipedia.org/wiki/Heapsort) | 堆排序 | $O(1)$ | $\\Omega(n\\log{n})$ / $\\Theta(n\\log{n})$ / $O(n\\log{n})$ | Basic<br />Unstable |\n| [Bubble Sort](https://en.wikipedia.org/wiki/Bubble_sort) | 冒泡排序 | $O(1)$ | $\\Omega(n)$ / $\\Theta(n^2)$ / $O(n^2)$ | Basic<br />Stable |\n| [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort) | 基数排序 | $O(n+k)$ | $\\Omega(nk)$ / $\\Theta(nk)$ / $O(nk)$ | Basic<br />Stable |\n| [Selection Sort](https://en.wikipedia.org/wiki/Selection_sort) | 选择排序 | $O(1)$ | $\\Omega(n^2)$ / $\\Theta(n^2)$ / $O(n^2)$ | Basic<br />Unstable |\n| [Shell Sort](https://en.wikipedia.org/wiki/Shellsort) | 希尔排序 | $O(1)$ | $\\Omega(n\\log{n})$ / $\\Theta(n(\\log{n})^2)$ / $O(n(\\log{n})^2)$ | Basic<br />Unstable |\n| [Insertion Sort](https://en.wikipedia.org/wiki/Insertion_sort) | 插入排序 | $O(1)$ | $\\Omega(n)$ / $\\Theta(n^2)$ / $O(n^2)$ | Basic<br />Stable |\n| [Tim Sort](https://en.wikipedia.org/wiki/Timsort) | 提姆排序 | $O(n)$ | $\\Omega(n)$ / $\\Theta(n\\log{n})$ / $O(n\\log{n})$ | Stable |\n| [Bucket Sort](https://en.wikipedia.org/wiki/Bucket_sort) | 桶排序 | $O(n)$ | $\\Omega(n+k)$ / $\\Theta(n+k)$ / $O(n^2)$ | Stable |\n| [Tree Sort](https://en.wikipedia.org/wiki/Tree_sort) | 树排序 | $O(n)$ | $\\Omega(n\\log{n})$ / $\\Theta(n\\log{n})$ / $O(n^2)$ | |\n| [Counting Sort](https://en.wikipedia.org/wiki/Counting_sort) | 计数排序 | $O(k)$ | $\\Omega(n+k)$ / $\\Theta(n+k)$ / $O(n+k)$ | Stable |\n| [Cube Sort](https://en.wikipedia.org/wiki/Cubesort) | 立方排序 | $O(n)$ | $\\Omega(n)$ / $\\Theta(n\\log{n})$ / $O(n\\log{n})$ | Stable |\n\n### Searching Algorithms\n\n- Graph with $\\lvert{V}\\rvert$ vertices and $\\lvert{E}\\rvert$ edges\n\n| Name | 算法名 | Space | Time | Note |\n| --- | --- | --- | --- | --- |\n| [Depth First Search](https://en.wikipedia.org/wiki/Depth-first_search) | 深度优先搜索 | $O(\\lvert{V}\\rvert)$ | - / $O(\\lvert{V}\\rvert+\\lvert{E}\\rvert)$ | |\n| [Breadth First Search](https://en.wikipedia.org/wiki/Breadth-first_search) | 广度优先搜索 | $O(\\lvert{V}\\rvert)$ | - / $O(\\lvert{V}\\rvert+\\lvert{E}\\rvert)$ | |\n| [Binary Search](https://en.wikipedia.org/wiki/Binary_search_algorithm) | 二分搜索 | $O(1)$ | $\\Theta(\\log{n})$ / $O(\\log{n})$ | Sorted array of n elements |\n| [Brute Force](https://en.wikipedia.org/wiki/Brute-force_search) | 穷举搜索 | $O(1)$ | $\\Theta(n)$ / $O(n)$ | Array |\n| [Shortest path by Bellman-Ford](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm) | | $O(\\lvert{V}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ / $O(\\lvert{V}\\rvert\\cdot\\lvert{E}\\rvert)$ | |\n| [Shortest path by Dijkstra (Min-heap)](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) | | $O(\\lvert{V}\\rvert)$ | $\\Theta((\\lvert{V}\\rvert+\\lvert{E}\\rvert)\\cdot\\log{\\lvert{V}\\rvert})$ / $O((\\lvert{V}\\rvert+\\lvert{E}\\rvert)\\cdot\\log{\\lvert{V}\\rvert})$ | |\n| Shortest path by Dijkstra (Unordered Array) | | $O(\\lvert{V}\\rvert)$ | $\\Theta(\\lvert{V}\\rvert^2)$ / $O(\\lvert{V}\\rvert^2)$ | |\n"
  },
  {
    "path": "topic/_test/python/__init__.py",
    "content": "from _test.python.test_base import TestBase\n"
  },
  {
    "path": "topic/_test/python/test_base.py",
    "content": "import unittest\nimport datetime\n\n\nclass TaskTimer:\n    def __init__(self):\n        self.reset_time()\n\n    def reset_time(self):\n        self.timestamp = datetime.datetime.now()\n\n    def print_duration(self):\n        duration = datetime.datetime.now() - self.timestamp\n        print(duration.microseconds // 10 / 100.0, 'ms')\n\n\nclass TestBase(unittest.TestCase):\n    MSG_TEMPLATE = '{status}: {msg}'\n\n    @classmethod\n    def setUpClass(cls):\n        print(cls.MSG_TEMPLATE.format(\n            status=cls.__name__,\n            msg='Starting tests...'\n        ))\n\n    @classmethod\n    def tearDownClass(cls):\n        print(cls.MSG_TEMPLATE.format(\n            status=cls.__name__,\n            msg='Finished tests.\\n'\n        ))\n\n    def setUp(self):\n        self.task_timer = TaskTimer()\n\n    def tearDown(self):\n        self.task_timer.print_duration()\n"
  },
  {
    "path": "topic/balanced_search_tree/python/__init__.py",
    "content": ""
  },
  {
    "path": "topic/balanced_search_tree/python/_helper.py",
    "content": ""
  },
  {
    "path": "topic/balanced_search_tree/python/red_black_tree.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/bit_manipulation/README.md",
    "content": "Bit Manipulation\n======\n\n## Modulo\n\n```python\n>>> a & 1 == a % 2\nTrue\n```\n\n## Division\n\n```python\n>>> a >> 1 == a // 2\nTrue\n```\n\n## 0 -> 1, 1 -> 0\n\noutput 1 if input 0\n\n```python\n>>> True ^ 1\n0\n>>> 1 ^ 1\n0\n>>> False ^ 1\n1\n>>> 0 ^ 1\n1\n```\n\n## To check a number is power of 2\n\nif a number is power of 2, then there is only 1 in the bit format in the number.\n\n```python\n>>> [(num & (num - 1)) == 0 for num in (4, 5, 11, 16, 21, 29, 32)]\n[True, False, False, True, False, False, True]\n```\n"
  },
  {
    "path": "topic/bit_manipulation/python/__init__.py",
    "content": "from bit_manipulation.python.calculator_in_bit import Calculator\n"
  },
  {
    "path": "topic/bit_manipulation/python/calculator_in_bit.py",
    "content": "\"\"\"\n1. Addition\n\n    - go through example: 1 + 5, that is 0001 + 0101\n\n    step1/ no carry(xor): 0001 ^ 0101 == 0100\n    step2/ considering carry(and + shift): (0001 & 0101) << 1 == 0010\n           the carry only occurs when the same digit is 1\n    step3/ repeat (1) and (2) til the result in (2) is 0\n\n    1 + 5 -> 0001 + 0101\n    r1: 0001 ^ 0101 == 0100, (0001 & 0101) << 1 == 0010\n    r2: 0100 ^ 0010 == 0110, (0100 & 0010) << 1 == 0000\n    got 0110 == 6\n\n    - deal with negative values\n\n    if a < 0 and b == 0,\n    => a wont be `&` (cannot enter iteration)\n    => a >> 31 == -1\n    => a ^ ~INT_RANGE got wrong number\n\n    so the simplest way is\n    `a >> 31 == 0` -> `a >> 31 <= 0`\n\n2. Subtraction\n\n    the simplest way is `a + (-b)`\n\n    to get the complement of `b`, that is `-b`\n    -b = ~b + 1\n\n3. Multiplication\n\n    in oct   | in bin\n      a  12  |   a  1100\n    x b  10  | x b  1010\n    -------- | ----------\n         00  |      0000\n        12   |     1100\n    -------- |    0000\n        120  |   1100\n             | ----------\n             |   1111000\n\n    r1/ 1100    * 0 =    0000\n    r2/ 11000   * 1 =   11000\n    r3/ 110000  * 0 =  000000\n    r4/ 1100000 * 1 = 1100000\n\n4. Division\n\n    if a // (2 ** i) >= b:\n    => quotient += 2 ** i\n    => a -= b * (2 ** i) for next iteration\n\"\"\"\n\n\nclass Calculator:\n    INT_RANGE = 0xFFFFFFFF\n\n    @classmethod\n    def _plus(cls, a, b):\n        \"\"\"\n        recursion\n        \"\"\"\n        if b == 0:\n            return a if a >> 31 <= 0 else a ^ ~cls.INT_RANGE\n\n        return cls._plus((a ^ b) & cls.INT_RANGE, (a & b) << 1)\n\n    @classmethod\n    def plus(cls, a, b):\n        \"\"\"\n        iteration\n        \"\"\"\n        while b != 0:\n            a, b = a ^ b, (a & b) << 1\n            a &= cls.INT_RANGE\n\n        return a if a >> 31 <= 0 else a ^ ~cls.INT_RANGE\n\n    @classmethod\n    def minus(cls, a, b):\n        return cls.plus(a, cls.plus(~b, 1))\n\n    @classmethod\n    def times(cls, a, b):\n        if not a or not b:\n            return 0\n\n        x = a if a > 0 else cls.plus(~a, 1)\n        y = b if b > 0 else cls.plus(~b, 1)\n\n        product = 0\n\n        while y:\n            if y & 1:\n                product = cls.plus(product, x)\n\n            x = x << 1\n            y = y >> 1\n\n        if a ^ b >= 0:\n            return product\n\n        return cls.plus(~product, 1)\n\n    @classmethod\n    def divide(cls, a, b):\n        if not b:\n            return float('inf') if a >= 0 else float('-inf')\n        if not a:\n            return 0\n\n        x = a if a > 0 else cls.plus(~a, 1)\n        y = b if b > 0 else cls.plus(~b, 1)\n\n        quotient = 0\n\n        for i in range(31, -1, -1):\n            if x >> i >= y:\n                quotient = cls.plus(quotient, 1 << i)\n                x = cls.minus(x, y << i)\n\n        if a ^ b >= 0:\n            return quotient\n\n        if x == 0:\n            return cls.plus(~quotient, 1)\n\n        return ~quotient\n"
  },
  {
    "path": "topic/bit_manipulation/python/calculator_in_bit__test.py",
    "content": "from _test.python import *\nfrom bit_manipulation.python import *\n\n\nclass TestBitCalculator(TestBase):\n    CASES = (\n        (-1, -1), (-1, 0), (-1, 1),\n        ( 0, -1), ( 0, 0), ( 0, 1),\n        ( 1, -1), ( 1, 0), ( 1, 1),\n\n        # (-0x80000000, -1),\n        # (-0x80000000,  1),\n        # ( 0x7FFFFFFF, -1),\n        # ( 0x7FFFFFFF,  1),\n        # (-1, -0x80000000),\n        # (-1,  0x7FFFFFFF),\n        # ( 1, -0x80000000),\n        # ( 1,  0x7FFFFFFF),\n\n        (-9, -7), (-9,  7),\n        ( 9, -7), ( 9,  7),\n        (-7, -9), (-7,  9),\n        ( 7, -9), ( 7,  9),\n\n        (-123,    0),\n        ( 123,    0),\n        (   0, -123),\n        (   0,  123),\n    )\n\n    def test_plus_recursion(self):\n        for a, b in self.CASES:\n            self.assertEqual(a + b, Calculator._plus(a, b))\n\n    def test_plus_iteration(self):\n        for a, b in self.CASES:\n            self.assertEqual(a + b, Calculator.plus(a, b))\n\n    def test_minus(self):\n        for a, b in self.CASES:\n            self.assertEqual(a - b, Calculator.minus(a, b))\n\n    def test_times(self):\n        for a, b in self.CASES:\n            self.assertEqual(a * b, Calculator.times(a, b))\n\n    def test_divide(self):\n        for a, b in self.CASES:\n            if not b:\n                c = float('inf') if a >= 0 else float('-inf')\n            elif not a:\n                c = 0\n            else:\n                c = a // b\n\n            self.assertEqual(c, Calculator.divide(a, b))\n"
  },
  {
    "path": "topic/complexity_analysis.md",
    "content": "Complexity Analysis\n======\n\n## Case #1\n\n- time: `O(N)`\n- REF: https://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%E2%8B%AF\n\n`N/2 + N/4 + N/8 + ... = N`\n\n```java\nint count = 0;\nfor (int i = N; i > 0; i /= 2) {\n  for (int j = 0; j < i; j++) {\n    count += 1;\n  }\n}\n```\n\n## Case #2\n\nIf X will always be a better choice for **large inputs**,\nthen we say that **an algorithm X is asymptotically more efficient than Y**.\n\n## Case #3\n\n- time: `O(N)`\n- the `j` go through that array only once.\n\n```java\nint j = 0;\nfor(int i = 0; i < n; ++i) {\n  while(j < n && arr[i] < arr[j]) {\n    j++;\n  }\n}\n```\n\n## Case #4\n\n- time: `O(2 ^ N)`\n- REF: https://math.stackexchange.com/questions/177405/prove-by-induction-2n-cn-0-cn-1-cdots-cn-n\n\n`C(n, 0) + C(n, 1) + ... + C(n, n) = 2 ^ n`\n"
  },
  {
    "path": "topic/dynamic_programming/README.md",
    "content": "Dynamic Programming\n======\n\n## Steps\n\n1. what is the meaning of `dp[i]`\n2. how to do initialization\n3. how you iterate that `dp`\n4. what is the returning\n\n## Space Optimization\n\n- rolling array, e.g., [lintcode/115_unique_paths_ii.py](../../lintcode/115_unique_paths_ii.py)\n- cache previous cell, e.g., [other/unique_paths_with_followups.py](../../other/unique_paths_with_followups.py)\n\n## Print Paths\n\n- 1D example: [leetcode/300_longest_increasing_subsequence.py](../../leetcode/300_longest_increasing_subsequence.py)\n- 2D example: [lintcode/168_burst_balloons.py](../../lintcode/168_burst_balloons.py)\n"
  },
  {
    "path": "topic/graph/README.md",
    "content": "Graph\n======\n\n## Graph Searching\n\n- Cyclic Graph: maintain a `seen` to record visited nodes.\n- Undirected Acyclic Graph: pick any point to start searching.\n- Directed Acyclic Graph: count `indegree` and do `Topological Sorting`.\n"
  },
  {
    "path": "topic/graph/python/__init__.py",
    "content": "from graph.python.union_find import UnionFind\n"
  },
  {
    "path": "topic/graph/python/union_find.py",
    "content": "class UnionFind:\n    def __init__(self):\n        self.nodes = {}\n\n    def union(self, u, v):\n        a = self.find(u)\n        b = self.find(v)\n\n        if a is not b:\n            self.nodes[b] = a\n\n        return a\n\n    def find(self, u):\n        if u not in self.nodes:\n            self.nodes[u] = u\n            return u\n        if self.nodes[u] is u:\n            return u\n\n        self.nodes[u] = self.find(self.nodes[u])\n        return self.nodes[u]\n"
  },
  {
    "path": "topic/graph/python/union_find__test.py",
    "content": "from _test.python import *\nfrom graph.python import UnionFind\n\n\nclass TestUnionFind(TestBase):\n    def test_init(self):\n        uf = UnionFind()\n\n        self.assertEqual(uf.nodes, {})\n\n    def test_union(self):\n        uf = UnionFind()\n\n        for i in range(1, 6):\n            query = uf.union(0, i)\n            self.assertEqual(query, 0)\n\n        for i in range(1, 6):\n            self.assertEqual(uf.nodes[i], 0)\n\n    def test_compression(self):\n        uf = UnionFind()\n\n        uf.union(2, 3)\n        uf.union(1, 2)\n\n        self.assertEqual(uf.nodes[3], 2)\n        self.assertEqual(uf.nodes[2], 1)\n\n        query = uf.find(3)\n\n        self.assertEqual(query, 1)\n        self.assertEqual(uf.nodes[3], 1)\n"
  },
  {
    "path": "topic/hash/python/__init__.py",
    "content": "from hash.python.hashtable import HashTable\nfrom hash.python.geohash import GeoHash\n"
  },
  {
    "path": "topic/hash/python/geohash.py",
    "content": "\"\"\"\nREF:\n\n- lintcode/529_geohash.py\n- lintcode/530_geohash_ii.py\n\n\nMain Concept: for encoding\n\n1. use binary search to convert `lng` and `lat` to `bincode`\n   1: up or right\n   0: down or left\n2. merge `lngcode` and `latcode` alternately into one `bincode`\n   `lngcode[0] + latcode[0] + lngcode[1] + ...`\n3. pick every 5 digit from `bincode` and convert that to base32 chars\n\"\"\"\n\n\nclass GeoHash:\n    def __init__(self):\n        ignored_chars = {ord(i) for i in 'ailo'}\n        base32 = [str(i) for i in range(10)]\n        base32.extend(\n            chr(i)\n            for i in range(ord('a'), ord('z') + 1)\n            if i not in ignored_chars\n        )\n        base32i = {base32[i]: i for i in range(len(base32))}\n\n        self.base32 = base32\n        self.base32i = base32i\n\n    def encode(self, latitude, longitude, precision=5):\n        digits = precision * 5 // 2 + 1\n        lngcode = self._pos_to_bin(longitude, digits, -180, 180)\n        latcode = self._pos_to_bin( latitude, digits,  -90,  90)\n\n        bincode = []\n        for i in range(digits):\n            bincode.append(lngcode[i])\n            bincode.append(latcode[i])\n\n        geohash = [\n            self.base32[int(''.join(bincode[i:i + 5]), 2)]\n            for i in range(0, len(bincode), 5)\n        ]\n\n        return ''.join(geohash[:precision])\n\n    def decode(self, geohash):\n        bincode = []\n        for i in geohash:\n            if i not in self.base32i:\n                return []\n            code = bin(self.base32i[i])[2:].rjust(5, '0')\n            bincode.extend(list(code))\n\n        n = len(bincode)\n        latcode = [bincode[i] for i in range(1, n, 2)]\n        lngcode = [bincode[i] for i in range(0, n, 2)]\n\n        return [\n            self._bin_to_pos(latcode,  -90,  90),\n            self._bin_to_pos(lngcode, -180, 180),\n        ]\n\n    def _bin_to_pos(self, bincode, start, end):\n        for i in bincode:\n            mid = (start + end) / 2.0\n\n            if i == '1':\n                start = mid\n            else:\n                end = mid\n\n        return (start + end) / 2.0\n\n    def _pos_to_bin(self, position, digits, start, end):\n        bincode = []\n\n        for _ in range(digits):\n            mid = (start + end) / 2.0\n\n            if mid < position:\n                bincode.append('1')\n                start = mid\n            else:\n                bincode.append('0')\n                end = mid\n\n        return bincode\n"
  },
  {
    "path": "topic/hash/python/geohash__test.py",
    "content": "from _test.python import *\nfrom hash.python import GeoHash\n\n\nclass TestGeoHash(TestBase):\n    CASES = (\n        ((39.92816697, 116.38954991), 'wx4g0s8q3jf9'),\n        ((51.5171437, -0.1337183), 'gcpvhfqth5sk'),\n        ((51.5160862, -0.1294528), 'gcpvj41wzw8b'),\n        ((37.4846102, -122.1516928), '9q9jhrggemb1'),\n        ((37.4219999, -122.0862462), '9q9hvu7wbq2s'),\n        ((-90, -180), '000000000000'),\n        ((-90, 0), '5bpbpbpbpbpb'),\n        ((-90, 180), 'pbpbpbpbpbpb'),\n        ((0, -180), '2pbpbpbpbpbp'),\n        ((0, 0), '7zzzzzzzzzzz'),\n        ((0, 180), 'rzzzzzzzzzzz'),\n        ((90, -180), 'bpbpbpbpbpbp'),\n        ((90, 0), 'gzzzzzzzzzzz'),\n        ((90, 180), 'zzzzzzzzzzzz'),\n    )\n\n    def test_encode(self):\n        gh = GeoHash()\n\n        for i, o in self.CASES:\n            self.assertEqual(gh.encode(*i, len(o)), o)\n\n    def test_decode(self):\n        EPS = 1e-6\n        gh = GeoHash()\n\n        for (lat1, lng1), i in self.CASES:\n            lat2, lng2 = gh.decode(i)\n            self.assertTrue(abs(lat1 - lat2) < EPS)\n            self.assertTrue(abs(lng1 - lng2) < EPS)\n"
  },
  {
    "path": "topic/hash/python/hashtable.py",
    "content": "class HashTable:\n    def __init__(self, cap=4000, power=31):\n        self.cap = cap\n        self.power = power\n        self.size = 0\n        self.table = [None] * self.cap\n\n    def __repr__(self):\n        return '{{{}}}'.format(\n            ', '.join(\n                repr(key) + ': ' + repr(val)\n                for key, val in self.items()\n            )\n        )\n\n    def __len__(self):\n        return self.size\n\n    def __setitem__(self, key, val):\n        self.set(key, val)\n\n    def __getitem__(self, key):\n        return self.get(key)\n\n    def __delitem__(self, key):\n        self.remove(key)\n\n    def __iter__(self):\n        for key, _ in self.items():\n            yield key\n\n    def keys(self):\n        for key, _ in self.items():\n            yield key\n\n    def values(self):\n        for _, val in self.items():\n            yield val\n\n    def items(self):\n        for head in self.table:\n            node = head\n\n            while node:\n                yield node.key, node.val\n                node = node.nxt\n\n    def set(self, key, val):\n        code = self._encode(key)\n\n        if not self.table[code]:\n            self.size += 1\n            self.table[code] = ListNode(key, val)\n            return\n\n        node = self.table[code]\n\n        while node and node.nxt and node.key != key:\n            node = node.nxt\n\n        if node.key == key:\n            node.val = val\n        else:\n            self.size += 1\n            node.nxt = ListNode(key, val)\n\n    def get(self, key):\n        code = self._encode(key)\n\n        if not self.table[code]:\n            raise KeyError(key)\n\n        node = self.table[code]\n\n        while node and node.key != key:\n            node = node.nxt\n\n        if node and node.key == key:\n            return node.val\n\n        raise KeyError(key)\n\n    def remove(self, key):\n        code = self._encode(key)\n\n        if not self.table[code]:\n            raise KeyError(key)\n\n        if self.table[code].key == key:\n            self.size -= 1\n            self.table[code] = self.table[code].nxt\n            return\n\n        node = self.table[code]\n\n        while node and node.nxt and node.nxt.key != key:\n            node = node.nxt\n\n        if node and node.nxt and node.nxt.key == key:\n            self.size -= 1\n            node.nxt = node.nxt.nxt\n            return\n\n        raise KeyError(key)\n\n    def _encode(self, key):\n        if isinstance(key, int):\n            return key % self.cap\n\n        code = 0\n\n        for c in key:\n            code = (code * self.power + ord(c)) % self.cap\n\n        return code\n\n\nclass ListNode:\n    def __init__(self, key, val, nxt=None):\n        self.key = key\n        self.val = val\n        self.nxt = nxt\n"
  },
  {
    "path": "topic/hash/python/hashtable__test.py",
    "content": "from _test.python import *\nfrom hash.python import HashTable\n\n\nclass TestHashTable(TestBase):\n    def test_operation(self):\n        d = HashTable()\n        self.assertEqual(len(d), 0)\n\n        d[1] = 1\n        self.assertEqual(d[1], 1)\n        self.assertEqual(len(d), 1)\n\n        d[2] = 2\n        self.assertEqual(d[2], 2)\n        self.assertEqual(len(d), 2)\n\n        d['ab'] = 3\n        self.assertEqual(d['ab'], 3)\n        self.assertEqual(len(d), 3)\n\n        d['ba'] = 4\n        self.assertEqual(d['ba'], 4)\n        self.assertEqual(len(d), 4)\n\n        self.assertEqual(d['ab'], 3)\n        self.assertEqual(len(d), 4)\n        del d['ab']\n        self.assertEqual(len(d), 3)\n        with self.assertRaises(KeyError):\n            d['ab']\n\n    def test_collision(self):\n        d = HashTable(4000, 31)\n        self.assertEqual(len(d), 0)\n\n        self.assertEqual(d._encode('ab'), d._encode('bC'))\n        self.assertEqual(d._encode('ab'), d._encode('c$'))\n\n        d['ab'] = 1\n        self.assertEqual(d['ab'], 1)\n        self.assertEqual(len(d), 1)\n\n        d['bC'] = 2\n        self.assertEqual(d['bC'], 2)\n        self.assertEqual(len(d), 2)\n\n        d['c$'] = 3\n        self.assertEqual(d['c$'], 3)\n        self.assertEqual(len(d), 3)\n\n        del d['bC']\n        self.assertEqual(len(d), 2)\n        with self.assertRaises(KeyError):\n            d['bC']\n\n        del d['c$']\n        self.assertEqual(len(d), 1)\n        with self.assertRaises(KeyError):\n            d['c$']\n            d['bC']\n\n        del d['ab']\n        self.assertEqual(len(d), 0)\n        with self.assertRaises(KeyError):\n            d['ab']\n            d['c$']\n            d['bC']\n"
  },
  {
    "path": "topic/heap/python/__init__.py",
    "content": "from heap.python.binary_hash_heap import BinaryHashHeap\nfrom heap.python.binary_heap import BinaryHeap\nfrom heap.python.lazy_removable_heapq import LazyRemovableHeapq\nfrom heap.python.removable_heapq import RemovableHeapq\n"
  },
  {
    "path": "topic/heap/python/binary_hash_heap.py",
    "content": "import collections\n\n\nclass BinaryHashHeap:\n    MSG_EMPTY_HEAP = 'access element from empty heap'\n\n    def __init__(self, iterable=None):\n        self.__heap = [0]\n        self.__size = 0\n        self.__idxs = collections.defaultdict(set)\n\n        if iterable:\n            self.heapify(iterable)\n\n    def __len__(self):\n        return self.__size\n\n    def __bool__(self):\n        return self.__size > 0\n\n    def heapify(self, iterable):\n        if not isinstance(iterable, collections.Iterable):\n            return\n\n        for val in iterable:\n            self.push(val)\n\n    def push(self, val):\n        self.__heap.append(val)\n        self.__size += 1\n        self.__idxs[val].add(self.__size)\n\n        self._siftdown(self.__size)\n\n    def pop(self):\n        if self.__size < 1:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        heap = self.__heap\n        idxs = self.__idxs\n\n        val = heap[1]\n        idxs[val].discard(1)\n        idxs[heap[-1]].discard(self.__size)\n        idxs[heap[-1]].add(1)\n\n        heap[1] = heap[-1]\n        heap.pop()\n\n        self.__size -= 1\n        self._siftup(1)\n        return val\n\n    def remove(self, val):\n        if not self.__idxs.get(val):\n            raise KeyError(val)\n\n        heap = self.__heap\n        idxs = self.__idxs\n\n        i = idxs[val].pop()\n        idxs[heap[-1]].discard(self.__size)\n        idxs[heap[-1]].add(i)\n\n        heap[i] = heap[-1]\n        heap.pop()\n\n        self.__size -= 1\n        self._siftup(i)\n\n    def top(self):\n        if self.__size < 1:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        return self.__heap[1]\n\n    def _siftdown(self, i):\n        heap = self.__heap\n\n        while i // 2 > 0:\n            j = i // 2\n\n            if heap[i] < heap[j]:\n                self._swap(i, j)\n\n            i = j\n\n    def _siftup(self, i):\n        heap = self.__heap\n        size = self.__size\n\n        while i * 2 <= size:\n            j = i * 2\n\n            if j + 1 <= size and heap[j + 1] < heap[j]:\n                j += 1\n\n            if heap[i] > heap[j]:\n                self._swap(i, j)\n\n            i = j\n\n    def _swap(self, i, j):\n        heap = self.__heap\n        idxs = self.__idxs\n\n        idxs[heap[i]].discard(i)\n        idxs[heap[j]].discard(j)\n\n        idxs[heap[i]].add(j)\n        idxs[heap[j]].add(i)\n\n        heap[i], heap[j] = heap[j], heap[i]\n"
  },
  {
    "path": "topic/heap/python/binary_heap.py",
    "content": "import collections\n\n\nclass BinaryHeap:\n    MSG_EMPTY_HEAP = 'access element from empty heap'\n\n    def __init__(self, iterable=None):\n        self.__heap = [0]\n        self.__size = 0\n\n        if iterable:\n            self.heapify(iterable)\n\n    def __len__(self):\n        return self.__size\n\n    def __bool__(self):\n        return self.__size > 0\n\n    def heapify(self, iterable):\n        if not isinstance(iterable, collections.Iterable):\n            return\n\n        for val in iterable:\n            self.push(val)\n\n    def push(self, val):\n        self.__heap.append(val)\n        self.__size += 1\n\n        self._siftdown(self.__size)\n\n    def pop(self):\n        if self.__size < 1:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        heap = self.__heap\n\n        val = heap[1]\n        heap[1] = heap[-1]\n        heap.pop()\n\n        self.__size -= 1\n        self._siftup(1)\n        return val\n\n    def top(self):\n        if self.__size < 1:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        return self.__heap[1]\n\n    def _siftdown(self, i):\n        heap = self.__heap\n\n        while i // 2 > 0:\n            j = i // 2\n\n            if heap[i] < heap[j]:\n                heap[i], heap[j] = heap[j], heap[i]\n\n            i = j\n\n    def _siftup(self, i):\n        heap = self.__heap\n        size = self.__size\n\n        while i * 2 <= size:\n            j = i * 2\n\n            if j + 1 <= size and heap[j + 1] < heap[j]:\n                j += 1\n\n            if heap[i] > heap[j]:\n                heap[i], heap[j] = heap[j], heap[i]\n\n            i = j\n"
  },
  {
    "path": "topic/heap/python/heap__test.py",
    "content": "from _test.python import *\nfrom heap.python import *\n\n\nclass TestHeap(TestBase):\n    def _test_heapify(self, Heap):\n        h = Heap([i for i in range(5)] * 2)\n\n        self.assertEqual(len(h), 10)\n        self.assertEqual(h.top(), 0)\n        self.assertEqual(\n            [h.pop() for _ in range(10)],\n            [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]\n        )\n        self.assertEqual(len(h), 0)\n\n        with self.assertRaises(IndexError):\n            h.pop()\n            h.pop()\n            h.pop()\n\n    def _test_push(self, Heap):\n        CASES = (1, 2, 3, 1, 3, 2, 0, 1, 4)\n        h = Heap()\n        self.assertEqual(len(h), 0)\n\n        for i in range(len(CASES)):\n            self.assertIsNone(h.push(CASES[i]))\n            self.assertEqual(len(h), i + 1)\n\n        self.assertEqual(\n            [h.pop() for _ in range(len(CASES))],\n            [0, 1, 1, 1, 2, 2, 3, 3, 4]\n        )\n        self.assertEqual(len(h), 0)\n\n        with self.assertRaises(IndexError):\n            h.pop()\n            h.pop()\n            h.pop()\n\n    def _test_pop(self, Heap):\n        CASES = list(range(10))\n        h = Heap(CASES)\n        self.assertEqual(len(h), 10)\n\n        for i in range(len(CASES)):\n            self.assertEqual(h.pop(), i)\n            self.assertEqual(len(h), len(CASES) - i - 1)\n\n        self.assertEqual(len(h), 0)\n\n        with self.assertRaises(IndexError):\n            h.pop()\n            h.pop()\n            h.pop()\n\n    def _test_remove(self, Heap):\n        CASES = (1, 2, 3, 1, 3, 2, 0, 1, 4)\n        h = Heap(CASES)\n        self.assertEqual(len(h), 9)\n\n        self.assertIsNone(h.remove(1))\n        self.assertEqual(len(h), 8)\n        self.assertIsNone(h.remove(1))\n        self.assertEqual(len(h), 7)\n        self.assertIsNone(h.remove(1))\n        self.assertEqual(len(h), 6)\n        with self.assertRaises(KeyError):\n            h.remove(1)\n            h.remove(5)\n            h.remove(1)\n\n        self.assertEqual(h.pop(), 0)\n        self.assertEqual(len(h), 5)\n\n        self.assertEqual(h.top(), 2)\n        self.assertEqual(len(h), 5)\n        self.assertIsNone(h.push(1))\n        self.assertEqual(len(h), 6)\n        self.assertEqual(h.top(), 1)\n        self.assertEqual(len(h), 6)\n        self.assertIsNone(h.remove(1))\n        self.assertEqual(h.top(), 2)\n        self.assertEqual(len(h), 5)\n\n        self.assertEqual(h.pop(), 2)\n        self.assertEqual(len(h), 4)\n        self.assertIsNone(h.remove(3))\n        self.assertEqual(len(h), 3)\n        self.assertIsNone(h.remove(2))\n        self.assertEqual(len(h), 2)\n        self.assertIsNone(h.remove(3))\n        self.assertEqual(len(h), 1)\n        self.assertEqual(h.pop(), 4)\n        self.assertEqual(len(h), 0)\n        with self.assertRaises(KeyError):\n            h.remove(-1)\n            h.remove(0)\n            h.remove(1)\n            h.remove(2)\n            h.remove(3)\n            h.remove(4)\n            h.remove(5)\n\n    def _test_top(self, Heap):\n        CASES = (1, 2, 3, 1, 3, 2, 0, 1, 4)\n        h = Heap(CASES)\n        self.assertEqual(len(h), 9)\n\n        for _ in range(len(CASES)):\n            self.assertEqual(h.top(), h.pop())\n\n        self.assertEqual(len(h), 0)\n\n        with self.assertRaises(IndexError):\n            h.top()\n            h.top()\n            h.top()\n\n    def _run_heap_test(self, Heap):\n        self._test_heapify(Heap)\n        self._test_push(Heap)\n        self._test_pop(Heap)\n        self._test_top(Heap)\n\n    def _run_removable_heap_test(self, Heap):\n        self._test_heapify(Heap)\n        self._test_push(Heap)\n        self._test_pop(Heap)\n        self._test_remove(Heap)\n        self._test_top(Heap)\n\n    def test_binary_hash_heap(self):\n        self._run_removable_heap_test(BinaryHashHeap)\n\n    def test_binary_heap(self):\n        self._run_heap_test(BinaryHeap)\n\n    def test_lazy_removable_heapq(self):\n        self._run_removable_heap_test(LazyRemovableHeapq)\n\n    def test_removable_heapq(self):\n        self._run_removable_heap_test(RemovableHeapq)\n"
  },
  {
    "path": "topic/heap/python/lazy_removable_heapq.py",
    "content": "import collections\nimport heapq\n\n\nclass LazyRemovableHeapq:\n    MSG_EMPTY_HEAP = 'access element from empty heap'\n\n    def __init__(self, iterable=None):\n        self.__heap = []\n        self.__size = 0\n        self.__cnts = collections.defaultdict(int)\n\n        if iterable:\n            self.heapify(iterable)\n\n    def __len__(self):\n        return self.__size\n\n    def __bool__(self):\n        return self.__size > 0\n\n    def heapify(self, iterable):\n        if not isinstance(iterable, collections.Iterable):\n            return\n\n        for val in iterable:\n            self.push(val)\n\n    def push(self, val):\n        heapq.heappush(self.__heap, val)\n        self.__size += 1\n        self.__cnts[val] += 1\n\n    def pop(self):\n        if self._is_empty():\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        val = heapq.heappop(self.__heap)\n        self.__size -= 1\n        self.__cnts[val] -= 1\n        return val\n\n    def remove(self, val):\n        if self._is_empty() or self.__cnts.get(val, 0) < 1:\n            raise KeyError(val)\n\n        self.__size -= 1\n        self.__cnts[val] -= 1\n\n    def top(self):\n        if self._is_empty():\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        return self.__heap[0]\n\n    def _is_empty(self):\n        while self.__heap and self.__cnts.get(self.__heap[0]) == 0:\n            heapq.heappop(self.__heap)\n\n        return self.__size == 0\n"
  },
  {
    "path": "topic/heap/python/removable_heapq.py",
    "content": "\"\"\"\nin `remove`, we cannot record index in hashmap to speed up\nsince the index in `heapq` changed all the time\n\"\"\"\n\n\nimport collections\nimport heapq\n\n\nclass RemovableHeapq:\n    MSG_EMPTY_HEAP = 'access element from empty heap'\n\n    def __init__(self, iterable=None):\n        self.__heap = []\n\n        if iterable:\n            self.heapify(iterable)\n\n    def __len__(self):\n        return len(self.__heap)\n\n    def __bool__(self):\n        return bool(self.__heap)\n\n    def heapify(self, iterable):\n        if not isinstance(iterable, collections.Iterable):\n            return\n\n        for val in iterable:\n            self.push(val)\n\n    def push(self, val):\n        heapq.heappush(self.__heap, val)\n\n    def pop(self):\n        if not self.__heap:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        return heapq.heappop(self.__heap)\n\n    def remove(self, val):\n        if not self.__heap:\n            raise KeyError(val)\n\n        i = 0\n        n = len(self.__heap)\n\n        while i < n and self.__heap[i] != val:\n            i += 1\n\n        if i >= n:\n            raise KeyError(val)\n\n        if i == n - 1:\n            self.__heap.pop()\n        else:\n            self.__heap[i] = self.__heap[-1]\n            self.__heap.pop()\n            heapq._siftup(self.__heap, i)\n\n    def top(self):\n        if not self.__heap:\n            raise IndexError(self.MSG_EMPTY_HEAP)\n\n        return self.__heap[0]\n"
  },
  {
    "path": "topic/language/javascript/README.md",
    "content": "JavaScript Syntax Note\n======\n\n## `Object`\n\n### To check a key is in object\n\n```js\n// `obj.hasOwnProperty`\n// check only the obj instance\n> obj.hasOwnProperty('key')\n\n\n// `in` operator\n// check the whole prototype chain\n> 'key' in obj\n\n> const someKey = 'key'\n> someKey in obj\n```\n\n## `Array`\n\n### To init array with fixed length\n\nNote that, the inited value passed into `fill` must be **IMMUTABLE**,\notherwise we can use `map` to init with mutable value.\n\n```js\n> new Array(3).fill(0)\n[ 0, 0, 0 ]\n> new Array(3).fill(0).map(_ => new Array(3).fill(0))\n[ [ 0, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ]\n```\n\nExplanation:\n\n```js\n> let nums\n\n// bad\n> nums = new Array(3).fill(new Array(3).fill(0))\n[ [ 0, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ]\n> nums[0][0] = 1\n1\n> nums\n[ [ 1, 0, 0 ], [ 1, 0, 0 ], [ 1, 0, 0 ] ]\n\n// good\n> nums = new Array(3).fill(0).map(_ => new Array(3).fill(0))\n[ [ 0, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ]\n> nums[0][0] = 1\n1\n> nums\n[ [ 1, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ]\n```\n\n### To sort\n\nThe default sorting is by **alphabetical order**.\nYou can also indicate a comparator if you want to sort it by custom order.\n\n```js\n> const nums = [1, 2, 4, 6, 4, 2, 2, 5, 1, 11, 22, 2, 3, 44]\nundefined\n> nums.sort()\n[ 1, 1, 11, 2, 2, 2, 2, 22, 3, 4, 4, 44, 5, 6 ]\n> nums.sort((a, b) => a - b)\n[ 1, 1, 2, 2, 2, 2, 3, 4, 4, 5, 6, 11, 22, 44 ]\n> nums.sort((a, b) => b - a)\n[ 44, 22, 11, 6, 5, 4, 4, 3, 2, 2, 2, 2, 1, 1 ]\n```\n\n### To override a existing array\n\n```js\n> let nums\nundefined\n> nums = [2, 1, 3, 4, 1, 2]\n[ 2, 1, 3, 4, 1, 2 ]\n> nums.splice(0, nums.length, ...[5, 6, 7, 1, 2, 3])\n[ 2, 1, 3, 4, 1, 2 ]\n> nums\n[ 5, 6, 7, 1, 2, 3 ]\n> nums.splice(0, nums.length)\n[ 5, 6, 7, 1, 2, 3 ]\n> nums\n[]\n```\n\n## `String`\n\n### To convert a string-number to a real number\n\n```js\n> +'123'\n123\n> +'-123'\n-123\n> -'123'\n-123\n> -'+123'\n-123\n> +'0'\n0\n> +'1'\n1\n> +'0.123'\n0.123\n> +'0.123a'\nNaN\n> +'0.123/2'\nNaN\n```\n\n## `Boolean`\n\n### To convert a boolean to `1` or `0`\n\n```js\n> +true\n1\n> +false\n0\n```\n\n## `Set`\n\n## `Map`\n"
  },
  {
    "path": "topic/language/javascript/traversal.md",
    "content": "Traversal\n======\n\n## To simulate a queue\n\nIt's also a good example to show how the pointer works for the loop.\n\n```js\n> const queue = [1]\nundefined\n> for (let i = 0; i < queue.length; i++) {\n...   if (i === 5) break\n...   queue.push(i)\n... }\nundefined\n> queue\n[ 1, 0, 1, 2, 3, 4 ]\n```\n\n```js\n> const queue = [1]\nundefined\n> let i = 0\nundefined\n> queue.forEach(num => {\n...   if (i === 5) return\n...   queue.push(i)\n... })\nundefined\n> queue\n[ 1, 0 ]\n```\n\n## To do BFS in level\n\n```js\n> const queue = [[0, 0]]\nundefined\n> const _queue = []\nundefined\n> const delta = [\n...   [0, -1], [0, 1],\n...   [-1, 0], [1, 0],\n... ]\nundefined\n>\n> const visited = {'0,0': 0}\nundefined\n> let steps = 0\nundefined\n> let i, x, y, _x, _y, key\nundefined\n>\n> while (queue.length && steps < 2) {\n... steps += 1\n...\n... for (i = 0; i < queue.length; i++) {\n...   [x, y] = queue[i]\n...\n...   delta.forEach(([dx, dy]) => {\n...     _x = x + dx\n...     _y = y + dy\n...     key = `${_x},${_y}`\n...\n...     if (visited[key] < steps) return\n...\n...     visited[key] = steps\n...     _queue.push([_x, _y])\n...   })\n... }\n...\n... queue.splice(0, queue.length, ..._queue)\n... _queue.splice(0, _queue.length)\n... }\n[ [ 0, -2 ], [ -1, -1 ], [ 1, -1 ], [ 0, 2 ],\n  [ -1, 1 ], [ 1, 1 ], [ -1, -1 ], [ -1, 1 ],\n  [ -2, 0 ], [ 1, -1 ], [ 1, 1 ], [ 2, 0 ] ]\n>\n> queue\n[ [ 0, -2 ], [ -1, -1 ], [ 1, -1 ], [ 0, 2 ],\n  [ -1, 1 ], [ 1, 1 ], [ -1, -1 ], [ -1, 1 ],\n  [ -2, 0 ], [ 1, -1 ], [ 1, 1 ], [ 2, 0 ] ]\n> visited\n{ '0,0': 0, '0,-1': 1, '0,1': 1, '-1,0': 1,\n  '1,0': 1, '0,-2': 2, '-1,-1': 2, '1,-1': 2,\n  '0,2': 2, '-1,1': 2, '1,1': 2, '-2,0': 2, '2,0': 2 }\n```\n"
  },
  {
    "path": "topic/language/php/README.md",
    "content": "PHP Syntax Note\n======\n\n## General\n\n- A PHP script starts with `<?php` and ends with `?>`. You can also use the shorthand PHP tags, `<?` and `?>`, as long as they're supported by the server.\n- PHP statements end with semicolons `;`.\n- Comment: single-line `//`, multi-line begins with `/*` and ends with `*/`.\n\n## Variable and Constant\n\n```php\n$variable_name = 'value';\necho $variable_name; // 'value'\n\n$var1 = 'var2';\n$var2 = 'value';\necho $$var1; // 'value'\n```\n\n- A variable name can only contain alpha-numeric characters and underscores. (`A-z`, `0-9`, and `_`)\n- A variable name must start with a letter or an underscore.\n- Variable names are case-sensitive. (`$name` and `$NAME` would be two different variables)\n\n```php\ndefine(CONSTANT_NAME, `value`, `case-insensitive`);\necho CONSTANT_NAME;\n```\n\n- Constants are similar to variables except that they cannot be changed or undefined after they've been defined.\n- name: Specifies the name of the constant.\n- value: Specifies the value of the constant.\n- case-insensitive: Specifies whether the constant name should be case-insensitive. Default is `false`.\n\n## Operators\n\n| Operator     | Example       | Note                                                         |\n| ------------ | ------------- | ------------------------------------------------------------ |\n| `+`          | `$a + $b`     | Addition. Supports `$a += $b`.                               |\n| `-`          | `$a - $b`     | Subtraction. Supports `$a -= $b`.                            |\n| `*`          | `$a * $b`     | Multiplication. Supports `$a *= $b`.                         |\n| `/`          | `$a / $b`     | Division (**NOT** Truncation Division). Supports `$a /= $b`. `10 / 3 == 3.3333...` |\n| `%`          | `$a % $b`     | Modulus. Supports `$a %= $b`. If you use floating point numbers with the modulus operator, they will be converted to **integers** before the operation. |\n| `++`         | `$a++; ++$a;` | post-increment / pre-increment. The difference is that the post-increment returns the original value **before** it changes the variable, while the pre-increment changes the variable first and then returns the value. |\n| `--`         | `$a--; --$a;` | post-decrement / pre-decrement.                              |\n| `==`         | `$a == $b`    | Returns `true` if `$a` is equal to `$b`.                     |\n| `===`        | `$a === $b`   | Returns `true` if `$a` is equal to `$b` and they are same type. |\n| `!=`         | `$a != $b`    | Returns `true` if `$a` is **NOT** equal to `$b`. Same to `$a <> $b`. |\n| `!==`        | `$a !== $b`   | Returns `true` if `$a` is **NOT** equal to `$b` **OR** they are **NOT** same type. |\n| `>` / `>=`   | `$a > $b`     | Greater than (or equal to).                                  |\n| `<` / `<=`   | `$a < $b`     | Less than (or equal to).                                     |\n| `&&` / `and` | `$a && $b`    | Returns `true` if **both** `$a` and `$b` are `true`.         |\n| `||` / `or`  | `$a || $b`    | Returns `true` if **either** `$a` and `$b` is `true`.        |\n| `xor`        | `$a xor $b`   | Returns `true` if **either** `$a` and `$b` is `true`, but **NOT both**. |\n| `!`          | `!$a`         | Returns `true` if `$a` is falsy.                             |\n\n## Template\n\n- `include`: continue if file was not found. `require`: throw error if file was not found.\n\n## `String`\n\n- `\"\"` supports escape character and html tag, but `''` do NOT.\n\n## `Array`\n\n- Numeric Array: generic array; Associative Array: like a hashtable.\n\n### Inited by values\n\n```php\n$arr = array('a', 'b', 'c');\necho $arr[0]; // 'a'\n$arr[0] = 'd';\necho $arr[0]; // 'd'\n\n$arr = array('a' => 1, 'b' => 2, 'c' => 3);\necho $arr['a']; // 1\n$arr['a'] = 4;\necho $arr['a']; // 4\n```\n\n### Inited by size\n\n```php\n// 1d array\n$arr = array_fill(0, 10, 1);\necho implode(',', $arr); // 1,1,1,1,1,1,1,1,1,1\n\n// 2d array\n$arr = array_fill(0, 5, array_fill(0, 5, 1));\necho $arr[0][0]; // 1\n$arr[0][0] = 2;\necho $arr[0][0]; // 2\n\necho implode(',', $arr[0]); // 2,1,1,1,1\necho implode(',', $arr[1]); // 1,1,1,1,1\necho implode(',', $arr[2]); // 1,1,1,1,1\necho implode(',', $arr[3]); // 1,1,1,1,1\necho implode(',', $arr[4]); // 1,1,1,1,1\n```\n"
  },
  {
    "path": "topic/language/python/README.md",
    "content": "Python Syntax Note\n======\n\n## General\n\n### Difference between `is` and `==`\n\n`is` will return True if two variables point to the same object,\n`==` if the objects referred to by the variables are equal.\n\n- example in `int` and `float`\n\nnote that, negative `int`/`float` is special case.\n\n```python\n>>> 10 != 10\nFalse\n>>> 10 is not 10\nFalse\n>>> 0 != 0\nFalse\n>>> 0 is not 0\nFalse\n>>> -9 != -9\nFalse\n>>> -9 is not -9\nTrue\n```\n\n- example in `str` and `bytes`\n\n```python\n# Python `2.7.13`, `2.7.14`\n>>> u'test' == 'test'\nTrue\n>>> u'test' is 'test'\nFalse\n\n# Python `3.6.0`, `3.6.3`\n>>> u'test' == 'test'\nTrue\n>>> u'test' is 'test'\nTrue\n```\n\n- example in `list`\n\n```python\n>>> a = [1, 2, 3]\n>>> b = [1, 2, 3]\n>>> a == b\nTrue\n>>> a is b\nFalse\n```\n\n### Always ensures that shared vars are **IMMUTABLE**\n\nin class\n\n```python\n# bad\n>>> class TestClass:\n...     x = {}\n>>> a = TestClass()\n>>> b = TestClass()\n>>> a.x\n{}\n>>> a.x[1] = 2\n>>> b.x\n{1: 2}\n\n# good\n>>> class TestClass:\n...     x = None\n...     def __init__(self):\n...             self.x = {}\n>>> a = TestClass()\n>>> b = TestClass()\n>>> a.x\n{}\n>>> a.x[1] = 2\n>>> b.x\n{}\n```\n\nin func\n\n```python\n# bad\n>>> def test_func(x=[]):\n...     x.append(1)\n...     return x\n>>> test_func()\n[1]\n>>> test_func()\n[1, 1]\n\n# good\n>>> def test_func(x=None):\n...     if x is None:\n...             x = []\n...     x.append(1)\n...     return x\n>>> test_func()\n[1]\n>>> test_func()\n[1]\n```\n\n### Private prop in `class`\n\n```python\n>>> class Test:\n...     def __init__(self):\n...             self.a = 1\n...             self._b = 2\n...             self.__c = 3\n...\n...     def get_c(self):\n...             return self.__c\n>>> t = Test()\n>>> t.a\n1\n>>> t._b\n2\n>>> t.__c\nAttributeError: 'Test' object has no attribute '__c'\n>>> t.get_c()\n3\n```\n\n### Hoisting\n\n```python\n# hoisting is in `for`, `if`, `while`\n>>> a\nNameError: name 'a' is not defined\n>>> i\nNameError: name 'i' is not defined\n>>> for i in range(10):\n...     a = 123\n>>> a\n123\n>>> i\n9\n\n# hoisting is NOT in list comprehensions\n>>> b\nNameError: name 'b' is not defined\n>>> [b for b in range(10)]\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n>>> b\nNameError: name 'b' is not defined\n\n# hoisting is NOT in `class`, `function`\n>>> c\nNameError: name 'c' is not defined\n>>> def test(a = 1):\n...     c = 2\n>>> test()\n>>> a\nNameError: name 'a' is not defined\n>>> c\nNameError: name 'c' is not defined\n```\n\n## String `str`, `bytes`\n\n### To find index\n\n```python\n>>> 'abc'.find('b')\n1\n>>> 'abc'.find('z')\n-1\n```\n\n### To split by multiple delimiters\n\n```python\n>>> import re\n>>> re.split(',\\s|\\s', \"Jimmy has an apple, it is on the table\")\n['Jimmy', 'has', 'an', 'apple', 'it', 'is', 'on', 'the', 'table']\n```\n\n## Number `int`, `float`\n\n### Using cascade comparison\n\n```python\n>>> 0 <= 2 < 3\nTrue\n>>> 0 <= 4 < 3\nFalse\n```\n\n### Be careful of the division\n\n```python\n# Python 2\n>>> 3 // 2\n1\n>>> 3 / 2\n1\n# to parse the result as float\n>>> 3 / 2.0\n1.5\n\n# Python 3\n>>> 3 // 2\n1\n>>> 3 / 2\n1.5\n```\n\nconclusion:\n\n```python\n# need int\n>>> 3 // 2\n1\n\n# need float\n>>> 3 / 2.0\n1.5\n```\n\n### Infinity\n\n```python\n# positive infinite\n>>> float('inf')\ninf\n\n# negative infinite\n>>> float('-inf')\n-inf\n```\n\n## List `list`\n\n### Iteration\n\n```python\n>>> A = [['a', 'b'], ['c', 'd']]\n>>> A\n[['a', 'b'], ['c', 'd']]\n>>> B = map(''.join, A)\n>>> B\n<map object at 0x10e901da0>\n>>> list(B)\n['ab', 'cd']\n```\n\n### Iteration in reversed order\n\n```python\n>>> A = list(range(10))\n>>> A\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n>>> A[::-1]\n[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n>>> [A[i] for i in range(len(A) - 1, -1, -1)]\n[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n```\n\n### To find index\n\n```python\n>>> ['a', 'b', 'c'].index('b')\n1\n>>> ['a', 'b', 'c'].index('z')\nValueError: 'z' is not in list\n```\n\n### To sort list\n\n```python\n>>> l = [(2,3), (2,-3), (-2,3), (-2,-3)]\n\n# 1 key\n>>> sorted(l, key=lambda i: i[0])\n[(-2, 3), (-2, -3), (2, 3), (2, -3)]\n\n# 2+ keys\n>>> sorted(l, key=lambda i: (i[0], i[1]))  # that is, `key=lambda i: i`\n[(-2, -3), (-2, 3), (2, -3), (2, 3)]\n```\n\n### To reverse list\n\n```python\n>>> origin = [100, 1, 1000, 10]\n\n>>> a = origin[:]\n>>> a.sort(reverse=True)\n>>> a\n[1000, 100, 10, 1]    # sorting involved\n>>> a is a\nTrue\n\n>>> b = origin[:]\n>>> _b = sorted(b, reverse=True)\n>>> _b\n[1000, 100, 10, 1]    # sorting involved\n>>> b is _b\nFalse\n\n>>> c = origin[:]\n>>> _c = reversed(c)  # <list_reverseiterator object>\n>>> list(_c)\n[10, 1000, 1, 100]    # only reversed\n>>> c is _c\nFalse\n\n>>> d = origin[:]\n>>> _d = d[::-1]\n>>> _d\n[10, 1000, 1, 100]    # only reversed\n>>> d is _d\nFalse\n```\n\n### To extend list\n\n```python\n>>> a = [1, 2, 3]\n>>> a\n[1, 2, 3]\n>>> a.extend((4, 5, 6))\n>>> a\n[1, 2, 3, 4, 5, 6]\n```\n\n### To extend list with existing items\n\nNote that this is copying the pointer, not value, that is,\nthe children must be **IMMUTABLE** in the list.\n\n```python\n>>> [1] * 3 * 3\n[1, 1, 1, 1, 1, 1, 1, 1, 1]\n>>> [1, 2, 3] * 3\n[1, 2, 3, 1, 2, 3, 1, 2, 3]\n>>> [[0] * 3 for _ in range(3)]\n[[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n```\n\nExplanation:\n\n```python\n# error\n>>> nums = [[0] * 3] * 3\n>>> nums\n[[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> nums[0][0] = 1\n>>> nums\n[[1, 0, 0], [1, 0, 0], [1, 0, 0]]\n\n# correct\n>>> nums = [[0] * 3 for _ in range(3)]\n>>> nums\n[[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> nums[0][0] = 1\n>>> nums\n[[1, 0, 0], [0, 0, 0], [0, 0, 0]]\n```\n\n### To extend existing list and create new one\n\n```python\n>>> a = [1]\n>>> b = a + [2]\n>>> a is b\nFalse\n```\n\n### To override mutable variable and keep the pointer if need\n\n```python\n>>> a = b = [1, 2, 3]\n>>> a is b\nTrue\n\n>>> b[:] = [4, 5, 6]\n>>> a\n[4, 5, 6]\n>>> a is b\nTrue\n\n>>> b = [7, 8, 9]\n>>> a\n[4, 5, 6]\n>>> a is b\nFalse\n```\n\n### To clone a list\n\n```python\n>>> a = [1, 2, 3]\n\n# shallow clone\n>>> b = a\n>>> b is a\nTrue\n>>> b = a[:]\n>>> b is a\nFalse\n\n# shallow clone\n>>> c = a\n>>> c is a\nTrue\n>>> c = a + []\n>>> c is a\nFalse\n\n# deep clone\n>>> a = [{'a': 1}]\n>>> from copy import deepcopy\n>>> b = deepcopy(a)\n>>> a[0]['a'] = 2\n>>> a, b\n([{'a': 2}], [{'a': 1}])\n```\n\n## Dict `dict`\n\n### Immutable Dict\n\n```python\n# set\n>>> from collections import namedtuple\n>>> ImmutableDict = namedtuple('ImmutableDict', ['k1', 'k2'])\n>>> D = ImmutableDict(1, 2)\n>>> D\nImmutableDict(k1=1, k2=2)\n\n# get\n>>> getattr(D, 'k1', -1)\n1\n>>> getattr(D, 'k3', -1)\n-1\n```\n\n### Multi-dimensional indexing in dict\n\n- with `tuple`\n\nnote that, since `tuple` is also **IMMUTABLE**.\n\n```python\n>>> d = {}\n>>> d[1, 2, 3] = 1\n>>> d[1, 2, 3]\n1\n>>> d[(1, 2, 3)]\n1\n>>> d\n{(1, 2, 3): 1}\n```\n\n- with `defaultdict`\n\n```python\n>>> import collections\n>>> d = collections.defaultdict(lambda: collections.defaultdict(int))\n>>> d[1][2] = 1\n>>> d[1][2]\n1\n>>> d\ndefaultdict(<function <lambda> at 0x10a889d90>, {1: defaultdict(<class 'int'>, {2: 1})})\n```\n\n### To clone a dict\n\n```python\n>>> a = {'a': 1, 'b': 2}\n\n# extend\n>>> a.update({'c': 3, 'd': {'e': 4}})\n>>> a\n{'a': 1, 'b': 2, 'c': 3, 'd': {'e': 4}}\n\n# shallow clone\n>>> b = a.copy()\n>>> a, b\n({'a': 1, 'b': 2, 'c': 3, 'd': {'e': 4}}, {'a': 1, 'b': 2, 'c': 3, 'd': {'e': 4}})\n>>> a['a'] = 99\n>>> a['d']['e'] = 99\n>>> a, b\n({'a': 99, 'b': 2, 'c': 3, 'd': {'e': 99}}, {'a': 1, 'b': 2, 'c': 3, 'd': {'e': 99}})\n\n# deep clone\n>>> from copy import deepcopy\n>>> b = deepcopy(a)\n>>> a, b\n({'a': 99, 'b': 2, 'c': 3, 'd': {'e': 99}}, {'a': 99, 'b': 2, 'c': 3, 'd': {'e': 99}})\n>>> a['a'] = 111\n>>> a['d']['e'] = 111\n>>> a, b\n({'a': 111, 'b': 2, 'c': 3, 'd': {'e': 111}}, {'a': 99, 'b': 2, 'c': 3, 'd': {'e': 99}})\n```\n"
  },
  {
    "path": "topic/language/python/matrix.md",
    "content": "Matrix Iteration\n======\n\n## To convert the 2D matrix to the 1D list\n\n```python\n# For any m * n matrix\n# 0 <= x < m, 0 <= y < n\n# The cell at `[i, j]` can be mapped to `k` in list\nk = i * n + j\n```\n\n## To iterate around the current cell\n\nmeans to visit the cell at the top/bottom/left/right\n\n```python\nVECTOR = (\n    (-1, 0),\n    ( 1, 0),\n    ( 0,-1),\n    ( 0, 1),\n)\n\nx, y = 1, 1\nfor dx, dy in VECTOR:\n    print(x + dx, y + dy)\n\n# 0, l: (0, 1)\n# 1, r: (2, 1)\n# 2, t: (1, 0)\n# 3, b: (1, 2)\n```\n\n## To avoid returning along the original path, just simply set the last visited cell to `'#'`\n\nsee [lintcode/132_word_search_ii.py](../lintcode/132_word_search_ii.py)\n\n## Traverse the half triangle in matrix\n\n```python\n>>> n = 4\n>>> arr = [[0] * n for _ in range(n)]\n>>> arr\n[[0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0]]\n\n>>> for x in range(n - 1, -1, -1):\n...     for y in range(x, n):\n...             arr[x][y] = 1\n>>> arr\n[[1, 1, 1, 1],\n [0, 1, 1, 1],\n [0, 0, 1, 1],\n [0, 0, 0, 1]]\n\n>>> for y in range(n - 1, -1, -1):\n...     for x in range(y, n):\n...             arr[x][y] = 2\n>>> arr\n[[2, 1, 1, 1],\n [2, 2, 1, 1],\n [2, 2, 2, 1],\n [2, 2, 2, 2]]\n\n>>> frozen_line = 2\n>>> for y in range(n - 1 - frozen_line, -1, -1):\n...     for x in range(y + frozen_line, n):\n...             arr[x][y] = 3\n>>> arr\n[[2, 1, 1, 1],\n [2, 2, 1, 1],\n [3, 2, 2, 1],\n [3, 3, 2, 2]]\n```\n\n### Need to init status by recursing from diagonal line\n\nsince sometimes we need to init status from bottom-left cell, see [lintcode/136_palindrome_partitioning.py](../lintcode/136_palindrome_partitioning.py)\n\n```python\n>>> n = 5\n>>> level = order = 0\n>>> arr = [[0] * n for _ in range(n)]\n>>> for y in range(n):\n...     order += 1\n...     arr[y][y] = order\n...     if y > 0:\n...             x = y - 1\n...             arr[x][y] = order\n>>> arr\n[[1, 2, 0, 0, 0],\n [0, 2, 3, 0, 0],\n [0, 0, 3, 4, 0],\n [0, 0, 0, 4, 5],\n [0, 0, 0, 0, 5]]\n\n>>> level = order = 0\n>>> for x in range(n - 1 - 2, -1, -1):\n...     level += 10\n...     order = 0\n...     for y in range(x + 2, n):\n...             order += 1\n...             arr[x][y] = level + order\n>>> arr\n[[ 1,  2, 31, 32, 33],\n [ 0,  2,  3, 21, 22],\n [ 0,  0,  3,  4, 11],\n [ 0,  0,  0,  4,  5],\n [ 0,  0,  0,  0,  5]]\n\n>>> level = order = 0\n>>> for size in range(1 + 2, n + 1):\n...     level += 10\n...     order = 0\n        # 0, 1, 2, 3, 4; n == 5, size == 3\n        # => set == {(0,1,2),(1,2,3),(2,3,4)}\n        # => i < 3\n        # => `i < n - size + 1` or `i <= n - size`\n...     for x in range(n - size + 1):\n...             order += 1\n...             y = x + size - 1\n...             arr[x][y] = level + order\n>>> arr\n[[ 1,  2, 11, 21, 31],\n [ 0,  2,  3, 12, 22],\n [ 0,  0,  3,  4, 13],\n [ 0,  0,  0,  4,  5],\n [ 0,  0,  0,  0,  5]]\n```\n"
  },
  {
    "path": "topic/language/python/runtime_of_builtins.md",
    "content": "The time-complexity of various operations in **CPython**\n======\n\nNote that,\n\n1. **CPython** is the official and most widespread implementation\n2. `n = len(data)`\n\n## Basic\n\n| Operation                    | Example              | Complexity | Notes                                    |\n| ---------------------------- | -------------------- | ---------- | ---------------------------------------- |\n| binding immutable value      | `a = 1`              | $O(1)$     |                                          |\n| simple operators on integers | `1 + 1`,<br>`2 == 2` | $O(1)$     | assume small integers unless explicitly told otherwise<br>(whose values are small: e.g., under 12 digits) |\n\n## List, Tuple\n\n`tuple` support all operations that do not mutate the data structure (and with the same complexity classes).\n\nWhen comparing two lists for equality, the complexity class above shows as $O(n)$, but in reality we would need to multiply this complexity by $O(==)$ where $O(==)$ is the complexity class for checking whether two values in the list are `==`. If they are ints, $O(==)$ would be $O(1)$; if they are strings, $O(==)$ in the worst case it would be $O(len(string))$. This issue applies any time an `==` check is done. We mostly will assume `==` checking on values in lists is $O(1)$: e.g., checking ints and small strings.\n\n| Operation             | Example               | Complexity    | Notes                                    |\n| --------------------- | --------------------- | ------------- | ---------------------------------------- |\n| index                 | `l[i]`                | $O(1)$        |                                          |\n| store                 | `l[i] = 0`            | $O(1)$        |                                          |\n| length                | `len(l)`              | $O(1)$        |                                          |\n| append                | `l.append(5)`         | $O(1)$        |                                          |\n| pop                   | `l.pop()`             | $O(1)$        | same as `l.pop(-1)`, popping at end      |\n| clear                 | `l.clear()`           | $O(1)$        | similar to `l = []`                      |\n| slice                 | `l[a:b]`              | $O(b-a)$      | `l[1:5]` -> $O(l)$<br>`l[:]` -> $O(len(l)-0)=O(n)$ |\n| extend                | `l.extend(t)`         | $O(m)$        | `m = len(t)`                             |\n| construction iterable | `list(l)`             | $O(n)$        |                                          |\n| check `==`, `!=`      | `l == t`              | $O(n)$        | note that, `is` -> $O(1)$, see [Difference between `is` and `==`](./python_syntax.md#difference-between-is-and-) |\n| insert                | `l[a:b] = t`          | $O(n)$        |                                          |\n| delete                | `del l[i]`            | $O(n)$        |                                          |\n| containment           | `v in l`/`v not in l` | $O(n)$        | searches list                            |\n| copy                  | `l.copy()`            | $O(n)$        | same as `l[:]` -> $O(n)$                 |\n| remove                | `l.remove(v)`         | $O(n)$        | remove `v` from `l` if `v` in `l` otherwise raise an exception |\n| pop                   | `l.pop(i)`            | $O(n)$        | $O(n-i)$<br>`l.pop(0)` -> $O(n)$         |\n| extreme value         | `min(l)`/`max(l)`     | $O(n)$        | searches list                            |\n| reverse               | `l.reverse()`         | $O(n)$        |                                          |\n| iteration             | `for v in l:`         | $O(n)$        |                                          |\n| sort                  | `l.sort()`            | $O(n\\log(n))$ | `key`/`reverse` mostly doesn't change    |\n| multiply              | `k * l`               | $O(k×n)$      |                                          |\n\n## collections.deque\n\nA `deque` (double-ended queue) is represented internally as a doubly linked list. (Well, a list of arrays rather than objects, for greater efficiency.) Both ends are accessible, but even looking at the middle is slow, and adding to or removing from the middle is slower still.\n\n| Operation  | Example           | Complexity | Notes                                    |\n| ---------- | ----------------- | ---------- | ---------------------------------------- |\n| append     | `q.append(1)`     | $O(1)$     |                                          |\n| appendleft | `q.appendleft(2)` | $O(1)$     |                                          |\n| pop        | `q.pop()`         | $O(1)$     |                                          |\n| popleft    | `q.popleft()`     | $O(1)$     |                                          |\n| extend     | `q.extend(t)`     | $O(m)$     | `m = len(t)`                             |\n| extendleft | `q.extendleft(t)` | $O(m)$     |                                          |\n| rotate     | `q.rotate(m)`     | $O(m)$     | `type(m) == int`<br>move the `m` children in right to left if `m > 0`<br>otherwise move from left to right |\n| copy       | `q.copy()`        | $O(n)$     |                                          |\n| remove     | `q.remove(x)`     | $O(n)$     |                                          |\n\n## Set\n\n`set` have many more operations that are $O(1)$ compared with lists and tuples. Not needing to keep values in a specific order in a set (which lists/tuples require) allows for faster set operations.\n\nFrozen sets support all operations that do not mutate the data structure (and with the same complexity classes).\n\n| Operation            | Example               | Complexity | Notes                                    |\n| -------------------- | --------------------- | ---------- | ---------------------------------------- |\n| length               | `len(s)`              | $O(1)$     |                                          |\n| add                  | `s.add(5)`            | $O(1)$     |                                          |\n| containment          | `v in s`/`v not in s` | $O(1)$     | compare to list/tuple -> $O(n)$          |\n| remove               | `s.remove(v)`         | $O(1)$     | remove `v` from `s` if `v` in `s` otherwise raise an exception<br>compare to list/tuple -> $O(n)$ |\n| discard              | `s.discard(v)`        | $O(1)$     | remove `v` from `s` even `v` not in `s` -> no exception |\n| pop                  | `s.pop()`             | $O(1)$     |                                          |\n| clear                | `s.clear()`           | $O(1)$     | similar to `s = set()`                   |\n| construction         | `set(l)`              | $O(n)$     | depends on length of iterable, that is `l` here |\n| check `==`, `!=`     | `s != t`              | $O(n)$     | `len(s)` must be same as `len(t)`<br>if not, return False in $O(1)$ |\n| `<=`/`<`             | `s <= t`              | $O(n)$     | issubset                                 |\n| `>=`/`>`             | `s >= t`              | $O(m)$     | `m = len(t)`<br>issuperset `s >= t` == `t <= s` |\n| union                | `s \\| t`              | $O(m+n)$   |                                          |\n| intersection         | `s & t`               | $O(m+n)$   |                                          |\n| difference           | `s - t`               | $O(m+n)$   |                                          |\n| symmetric difference | `s ^ t`               | $O(m+n)$   | see [Symmetric Difference @wikipedia](https://en.wikipedia.org/wiki/Symmetric_difference) |\n| iteration            | `for v in s:`         | $O(n)$     |                                          |\n| copy                 | `s.copy()`            | $O(n)$     |                                          |\n\n## Dict\n\nMost `dict` operations are $O(1)$.\n\n`defaultdict` support all operations that dicts support, with the same complexity classes (because it inherits all the operations); this assumes that calling the constructor when a values isn't found in the defaultdict is $O(1)$ - which is true for `int()`, `list()`, `set()`, ... (the things we commonly use)\n\n| Operation               | Example       | Complexity | Notes                                    |\n| ----------------------- | ------------- | ---------- | ---------------------------------------- |\n| index                   | `d[k]`        | $O(1)$     |                                          |\n| store                   | `d[k] = v`    | $O(1)$     |                                          |\n| length                  | `len(d)`      | $O(1)$     |                                          |\n| delete                  | `del d[k]`    | $O(1)$     |                                          |\n| `get`/`setdefault`      | `d.get()`     | $O(1)$     |                                          |\n| pop                     | `d.pop(k)`    | $O(1)$     |                                          |\n| pop item                | `d.popitem()` | $O(1)$     |                                          |\n| clear                   | `d.clear()`   | $O(1)$     | similar to `s = {}` or `s = dict()`      |\n| `keys`/`values`/`items` | `d.keys()`    | $O(1)$     |                                          |\n| construction            | `dict(t)`     | $O(n)$     | `n = len(t)`<br>the interface of `t`: `Iterable[Iterable]`<br>example: `((1, 2), (2, 3), (4, 5), ('a', 6))` |\n| iteration               | `for v in d:` | $O(n)$     | same as `for v in d.keys()`<br>all forms: `keys`, `values`, `items` |\n\n## Reference\n\n- [Complexity of Python Operations](https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt)\n- [TimeComplexity - Python Wiki](https://wiki.python.org/moin/TimeComplexity)\n"
  },
  {
    "path": "topic/language/python/traversal.md",
    "content": "Traversal\n======\n\n## Iterate an iterable item\n\n- `for`: the pointer of an iterable item will be **UNCHANGED** after start\n- `while`: the pointer of an iterable item will be **RE-FETCHED** before every loop start\n\n### Dynamically extend an iterable item in `for` loop\n\n- scenario: BFS\n- example:\n  - [binary_tree_serialization.py](../module/binary_tree_serialization.py)\n- the behavior below just like `queue`\n\n```python\n>>> arr = [0]\n>>> for child in arr:\n...     if len(arr) > 5:\n...             break\n...     arr.append(1)\n>>> arr\n[0, 1, 1, 1, 1, 1]\n```\n\n### Dynamically re-assign an iterable item\n\n1. Normal Form\n\n- scenario: BFS in level traversal\n- example:\n  - [binary_tree_preorder_traversal.py](../module/binary_tree_preorder_traversal.py)\n  - [69_binary_tree_level_order_traversal.py](../lintcode/69_binary_tree_level_order_traversal.py)\n  - [598_zombie_in_matrix.py](../lintcode/598_zombie_in_matrix.py)\n\n```python\n>>> arr = [{\n...     'val': 1,\n...     'left': {'val': 2, 'left': None, 'right': None},\n...     'right': {'val': 3, 'left': None, 'right': None},\n... }]\n>>> _arr = None\n>>> level = 0\n>>> while arr:\n...     level += 1\n...     _arr = []\n...     for child in arr:\n...         if child['left']:\n...             _arr.append(child['left'])\n...         if child['right']:\n...             _arr.append(child['right'])\n...     arr = _arr\n>>> level\n2\n```\n\n2. Dedup Form\n\n- scenario: BFS in level traversal if the node may be visited twice. e.g., graph.\n- example:\n  - [lintcode/120_word_ladder.py](../lintcode/120_word_ladder.py)\n  - [lintcode/121_word_ladder_ii.py](../lintcode/121_word_ladder_ii.py)\n  - [lintcode/531_six_degrees.py](../lintcode/531_six_degrees.py)\n"
  },
  {
    "path": "topic/language/sql/README.md",
    "content": "SQL (Structured Query Language)\n======\n\n**SQL** is used to access and manipulate a **database**.\n\n**MySQL** is a program that understands **SQL**.\n\nSQL can:\n\n- insert, update, or delete records in a database.\n- create new databases, table, stored procedures, views.\n- retrieve data from a database, etc.\n\nSQL is an ANSI (American National Standards Institute) standard, but there are different versions of the SQL language.\n\nMost SQL database programs have their own proprietary extensions in addition to the SQL standard, but all of them support the major commands.\n\n## Concept\n\nA **database** is a collection of data that is organized in a manner that facilitates ease of access, as well as efficient management and updating.\n\nA database is made up of **tables** that store relevant information.\n\nA table stores and displays data in a structured format consisting of **columns** and **rows** that are similar to those seen in Excel spreadsheets.\n\n### Primary Key\n\nA primary key is a field in the table that uniquely identifies the table records.\n\nThe primary key's main features:\n\n- It must contain a **unique value** for each row.\n- It cannot contain `NULL` values.\n\nNote that,\n\n- Tables are limited to **ONE** primary key each.\n- The primary key's value must be different for each row.\n\n## Syntax\n\n### Logical Operators\n\nNote that, to compare with a text value, you need to surround the text that appears in the statement with **single quotation marks (')**.\n\n| Operators         | Notes                                                        |\n| ----------------- | ------------------------------------------------------------ |\n| `=`               | Equal                                                        |\n| `!=`              | Not equal                                                    |\n| `>`               | Greater than                                                 |\n| `<`               | Less than                                                    |\n| `>=`              | Greater than or equal                                        |\n| `<=`              | Less than or equal                                           |\n| `BETWEEN a AND b` | Between an inclusive range, that is, `a <= x <= b`           |\n| `AND`             | True if **both** expressions are True                        |\n| `OR`              | True if **either** expressions is True                       |\n| `a IN (b, c, d)`  | True if the operand is equal to one of a list of expressions |\n| `NOT`             | Returns True if expression is not True                       |\n| `a LIKE pattern`  | SQL **pattern** matching enables you to use `_` to match any single character and `%` to match an arbitrary number of characters (including zero characters). |\n\n### Arithmetic Operators\n\n| Operators | Notes          |\n| --------- | -------------- |\n| `+`       | addition       |\n| `-`       | subtraction    |\n| `*`       | multiplication |\n| `/`       | division       |\n\n### Data Types\n\n| Type           | Category      | Notes                                                        |\n| -------------- | ------------- | ------------------------------------------------------------ |\n| `int`          | Numeric       | A normal-sized integer that can be signed or unsigned.       |\n| `float(n, d)`  | Numeric       | A floating-point number that cannot be unsigned. You can optionally define the display length (`n`) and the number of decimals (`d`). |\n| `double(n, d)` | Numeric       | A double precision floating-point number that cannot be unsigned. You can optionally define the display length (`n`) and the number of decimals (`d`). |\n| `date`         | Date and Time | A date in `YYYY-MM-DD` format.                               |\n| `datetime`     | Date and Time | A date and time combination in `YYYY-MM-DD HH:MM:SS` format. |\n| `time`         | Date and Time | A time in `HH:MM:SS` format.                                 |\n| `timestamp`    | Date and Time | A timestamp, calculated from midnight, January 1, 1970.      |\n| `char(n)`      | String        | Fixed-length (`n`) character string. Size is specified in parenthesis. Max 255 bytes. |\n| `varchar(n)`   | String        | Variable-length(`n`)character string. Max size is specified in parenthesis. |\n| `blob`         | String        | **Binary Large Objects** and are used to store large amounts of binary data, such as images or other types of files. |\n| `text`         | String        | Large amount of text data.                                   |\n\n### Multiple Queries\n\nSQL allows to run multiple queries or commands at the same time.\n\nRemember to end each SQL statement with a **semicolon** to indicate that the statement is complete and ready to be interpreted.\n\nIn this tutorial, we will use **semicolon** at the end of each SQL statement.\n\n```sql\nSELECT FirstName FROM customers;\nSELECT City FROM customers;\n```\n\n### Case Sensitivity\n\nSQL is case **insensitive**.\n\nIt is common practice to write all SQL commands in **upper-case**.\n\n### Separator\n\nA single SQL statement can be placed on one or more text lines. In addition, multiple SQL statements can be combined on a single text line.\n\nWhite spaces and multiple lines are ignored in SQL. However, it is recommended to avoid unnecessary white spaces and lines.\n\nCombined with proper spacing and indenting, breaking up the commands into logical lines will make your SQL statements much easier to read and maintain.\n\n## Command\n\n### Database\n\n| Commands         | Notes                                     |\n| ---------------- | ----------------------------------------- |\n| `SHOW DATABASES` | list the databases managed by the server. |\n\n### Table\n\n#### SQL constraints\n\n- `NOT NULL` - Indicates that a column cannot contain any NULL value.\n- `UNIQUE` - Does not allow to insert a duplicate value in a column. The `UNIQUE` constraint maintains the uniqueness of a column in a table. More than one `UNIQUE` column can be used in a table.\n- `AUTO_INCREMENT` - Auto-increment allows a unique number to be generated when a new record is inserted into a table. By default, the starting value for `AUTO_INCREMENT` is 1, and it will increment by 1 for each new record.\n- `PRIMARY KEY` - Enforces the table to accept unique data for a specific column and this constraint create a unique index for accessing the table faster.\n- `CHECK` - Determines whether the value is valid or not from a logical expression.\n- `DEFAULT` - While inserting data into a table, if no value is supplied to a column, then the column gets the value set as `DEFAULT`.\n\n#### Views\n\nIn SQL, a VIEW is a **virtual table** that is based on the result-set of an SQL statement.\n\nA view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database.\n\nA view always shows up-to-date data! The database engine uses the view's SQL statement to recreate the data each time a user queries a view.\n\nViews allow us to:\n\n- Structure data in a way that users or classes of users find natural or intuitive.\n- Restrict access to the data in such a way that a user can see and (sometimes) modify exactly what they need and no more.\n- Summarize data from various tables and use it to generate reports.\n\n| Commands                                                     | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| `SHOW TABLES`                                                | display all of the tables in the currently selected MySQL database. |\n| `CREATE TABLE Users ( UserID int NOT NULL AUTO_INCREMENT, FirstName varchar(40) NOT NULL, LastName varchar(40) NOT NULL, PRIMARY KEY(UserID) )` | Note the **parentheses** in the syntax. When inserting a new record into the Users table, it's not necessary to specify a value for the `UserID` column; a unique new value will be added automatically. |\n| `DROP TABLE table`                                           | delete the entire table                                      |\n| `RENAME TABLE table TO new_name`                             | rename the entire table                                      |\n| `CREATE VIEW view AS (SELECT col FROM table WHERE condition)` | The `SELECT` query can be as complex as you need it to be. It can contain multiple JOINS and other commands. |\n| `CREATE OR REPLACE VIEW view AS (subquery)`                  | update a view                                                |\n| `DROP VIEW view`                                             | delete a view                                                |\n\n### Column\n\n| Commands                                        | Notes                                                        |\n| ----------------------------------------------- | ------------------------------------------------------------ |\n| `SHOW COLUMNS FROM table`                       | display information about the columns in a given table.      |\n| `SELECT col AS col2 FROM table`                 | assign a custom name to the resulting column using the `AS` keyword. |\n| `ALTER TABLE table ADD new_col int`             | add columns in an existing table. All rows will have the default value in the newly added column, which, in this case, is `NULL`. |\n| `ALTER TABLE table DROP COLUMN col`             | delete the column named col in the table. The column, along with all of its data, will be completely removed from the table. |\n| `ALTER TABLE table CHANGE col new_name type(n)` | rename the column called col to new_name                     |\n\n### Basic Query\n\n| Commands                                                     | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| `SELECT col FROM table`                                      | select data from a given table.                              |\n| `SELECT col1, col2 FROM table`                               | select data from a given table. Do not put a comma after the **last** column name. |\n| `SELECT table.col FROM table`                                | you can provide the table name prior to the column name, by separating them with a **dot**. The term for the above-mentioned syntax is called the **fully qualified name** of that column. This form of writing is especially useful when working with multiple tables that may share the same column names. |\n| `SELECT * FROM table`                                        | retrieve all of the information contained in your table, place an **asterisk (\\*)** sign after the `SELECT` command, rather than typing in each column names separately. |\n| `SELECT col FROM table WHERE col > (SELECT AVG(col) FROM table)` | A single subquery will return the same result more easily.   |\n\n### WHERE\n\n| Commands                              | Notes                                                        |\n| ------------------------------------- | ------------------------------------------------------------ |\n| `SELECT * FROM table WHERE condition` | extract only those records that fulfill a specified criterion. |\n\n### DISTINCT and LIMIT\n\n| Commands                                        | Notes                                                        |\n| ----------------------------------------------- | ------------------------------------------------------------ |\n| `SELECT DISTINCT col1, col2 FROM table`         | conjunction with `SELECT` to eliminate all duplicate records and return only unique ones |\n| `SELECT col1, col2 FROM table LIMIT cnt`        | retrieve the first `cnt` records from the table              |\n| `SELECT col1, col2 FROM table LIMIT start, cnt` | pick up `cnt` records, starting from the `start` position. the position is **zero-based** counting, so the position 3 == the fourth record. |\n\n### ORDER BY\n\n| Commands                                  | Notes                                                        |\n| ----------------------------------------- | ------------------------------------------------------------ |\n| `SELECT * FROM table ORDER BY col1, col2` | **sort** the returned data. By default, the ORDER BY keyword sorts the results in **ascending** order. |\n| `SELECT * FROM table ORDER BY col1 DESC`  | The `DESC` keyword sorts results in **descending** order. Similarly, `ASC` sorts the results in **ascending** order. |\n\n### JOIN\n\n| Commands                                                     | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| `SELECT tb1.a, tb2.a FROM tb1, tb2 WHERE tb1.a = tb2.a`      | Specify multiple table names in the FROM by comma-separating them. |\n| `SELECT tb1.col1, tb2.col1 FROM tb1 INNER JOIN tb2 ON tb1.col1 = tb2.col1` | `INNER JOIN` is equivalent to `JOIN`. It returns rows when there is a match between the tables. Note the `ON` keyword for specifying the inner join condition. |\n| `SELECT customers.Name, items.Name FROM customers LEFT OUTER JOIN items ON customers.ID = items.Seller_id` | The `OUTER` keyword is optional, and can be omitted. The `LEFT JOIN` returns all rows from the left table, even if there are no matches in the right table. This means that if there are no matches for the `ON` clause in the table on the right, the join will still return the rows from the first table in the result. If no match is found for a particular row, `NULL` is returned. |\n| `SELECT col1 FROM tb1 UNION SELECT col2 FROM tb2`            | `UNION` combines multiple datasets into a single dataset, and removes any existing duplicates. `UNION ALL` combines multiple datasets into one dataset, but does not remove duplicate rows. `UNION ALL` is faster than `UNION`, as it does not perform the duplicate removal operation over the data set.<br>The `UNION` operator is used to combine the result-sets of two or more `SELECT` statements. All `SELECT` statements within the `UNION` must have the **same number of columns**. The columns must also have the same **data types**. Also, the columns in each `SELECT` statement must be **in the same order**.<br>If your columns don't match exactly across all queries, you can use a NULL (or any other) value. |\n\n### INSERT/UPDATE/DELETE\n\n| Commands                                                    | Notes                                                        |\n| ----------------------------------------------------------- | ------------------------------------------------------------ |\n| `INSERT INTO table VALUES (val1, val2, ...)`                | add **new rows** of data to a table in the database. Make sure the order of the values is in the same order as the columns in the table. When inserting records into a table using the SQL `INSERT` statement, you must provide a value for every column that does not have a default value, or does not support `NULL`. |\n| `INSERT INTO table (col2, col1) VALUES (val2, val1)`        | You can specify your own column order, as long as the values are specified in the same order as the columns. The **missing** column for that row automatically became its default value. |\n| `UPDATE table SET col1 = val1, col2 = val2 WHERE condition` | allows us to alter data in the table. You specify the column and its new value in a comma-separated list after the `SET` keyword. If you omit the `WHERE` clause, **ALL records** in the table will be updated! |\n| `DELETE FROM table WHERE condition`                         | remove data from your table. If you omit the `WHERE` clause, **ALL records** in the table will be deleted! The `DELETE` statement removes the data from the table permanently. |\n\n### Functions\n\n| Commands                                                     | Notes                                                        |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| `SELECT CONCAT(a, ',', b) FROM table`                        | concatenate two or more text values and returns the concatenating string. |\n| `SELECT FirstName, UPPER(LastName) AS LastName FROM employees` | The `UPPER` function converts all letters in the specified string to uppercase. The `LOWER` function converts the string to lowercase. If there are characters in the string that are not letters, this function will have no effect on them. |\n| `SELECT Salary, SQRT(Salary) FROM employees`                 | calculate the square root of each Salary                     |\n| `SELECT AVG(Salary) FROM employees`                          | returns the average value of a numeric column                |\n| `SELECT SUM(Salary) FROM employees`                          | get the sum of all of the salaries in the employees table    |\n| `SELECT MIN(Salary) AS Salary FROM employees`                | return the minimum value of an expression                    |\n"
  },
  {
    "path": "topic/linked_list/README.md",
    "content": "Linked List\n======\n\n## Common Rule\n\n- If the list is cyclic, the 2-pace pointer will eventually meet the 1-pace. see [lintcode/102_linked_list_cycle.py](../lintcode/102_linked_list_cycle.py)\n- If there is a intersection node, the steps from the first node is equal to from meet node plus 1. see [lintcode/103_linked_list_cycle_ii.py](../lintcode/103_linked_list_cycle_ii.py)\n- If its a list, the middle node is the 1-pace pointer when the 2-pace pointer has traversed the list. see [lintcode/98_sort_list.py](../lintcode/98_sort_list.py)\n\n## Reverse Linked List\n\n- with two extra vars\n\n```python\n>>> cur = nxt = None\n>>> while head:\n...     nxt = head.next\n...     head.next = cur\n...     cur = head\n...     head = nxt\n```\n\n- with one extra var (**Python only**)\n\n```python\n>>> cur = None\n>>> while head:\n...     head.next, cur, head = cur, head, head.next\n```\n"
  },
  {
    "path": "topic/linked_list/python/__init__.py",
    "content": "from linked_list.python.cyclic_list import CyclicList\nfrom linked_list.python.cyclic_doubly_list import CyclicDoublyList\n\nfrom linked_list.python.dummy_tail_list import DummyTailList\nfrom linked_list.python.dummy_tail_doubly_list import DummyTailDoublyList\n\nfrom linked_list.python.head_tail_list import HeadTailList\nfrom linked_list.python.head_tail_doubly_list import HeadTailDoublyList\n\nfrom linked_list.python.two_dummy_list import TwoDummyList\nfrom linked_list.python.two_dummy_doubly_list import TwoDummyDoublyList\n"
  },
  {
    "path": "topic/linked_list/python/_helper.py",
    "content": "\"\"\"\napi doc of Class java.util.LinkedList\nhttps://courses.cs.washington.edu/courses/cse341/98au/java/jdk1.2beta4/docs/api/java/util/LinkedList.html\n\"\"\"\nfrom abc import ABC, abstractmethod\nimport collections\n\n\nclass ListNode:\n    def __init__(self, val, nxt=None):\n        self.val = val\n        self.nxt = nxt\n\n\nclass DoublyListNode:\n    def __init__(self, val, pre=None, nxt=None):\n        self.val = val\n        self.pre = pre\n        self.nxt = nxt\n\n\nclass ListBase(ABC):\n    def __repr__(self):\n        return repr(self.to_list())\n\n    def __str__(self):\n        return str(self.to_list())\n\n    def __bool__(self):\n        return bool(self._get_size())\n\n    def __len__(self):\n        return self._get_size()\n\n\n    def to_list(self):\n        \"\"\"\n        :rtype: List[any]\n        \"\"\"\n        return list(self.__iter__())\n\n    def contains(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: bool\n        \"\"\"\n        for node in self.__iter__():\n            if node is obj:\n                return True\n\n        return False\n\n    def get_first(self):\n        \"\"\"\n        :rtype: any\n        \"\"\"\n        return self.get(0)\n\n    def get_last(self):\n        \"\"\"\n        :rtype: any\n        \"\"\"\n        return self.get(-1)\n\n    def add_first(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: void\n        \"\"\"\n        self.add(obj, 0)\n\n    def add_last(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: void\n        \"\"\"\n        self.add(obj, -1)\n\n    def remove_first(self):\n        \"\"\"\n        :rtype: any\n        \"\"\"\n        return self.remove(0)\n\n    def remove_last(self):\n        \"\"\"\n        :rtype: any\n        \"\"\"\n        return self.remove(-1)\n\n    def _check_index(self, index, raise_error=False):\n        \"\"\"\n        :type index: int\n        :type raise_error: bool\n        :rtype: bool\n\n        return True if index is valid\n        return False if invalid and NO need raise_error\n        raise IndexError if invalid and need raise_error\n        \"\"\"\n        size = self._get_size()\n\n        if any((\n            index >= 0 and index < size,\n            index < 0 and -index <= size,\n        )):\n            # is valid\n            return True\n\n        if raise_error:\n            raise IndexError('linked list index out of range')\n\n        return False\n\n\n    @abstractmethod\n    def __iter__(self):\n        pass\n\n    @abstractmethod\n    def set(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: any\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def get(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def add(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: void\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def add_all(self, objs, index=-1):\n        \"\"\"\n        :type objs: Iterable\n        :type index: int\n        :rtype: void\n        \"\"\"\n        if not isinstance(objs, collections.Iterable):\n            raise ValueError('Oops! passed-in objs was not iterable.')\n\n    @abstractmethod\n    def remove(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def last_index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def clear(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def clone(self):\n        \"\"\"\n        :rtype: LinkedList\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def sort(self, key=None):\n        \"\"\"\n        :type key: function\n        :rtype: void\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def _get_size(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def _get_node(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: ListNode\n        \"\"\"\n        pass\n"
  },
  {
    "path": "topic/linked_list/python/cyclic_doubly_list.py",
    "content": "\"\"\"\nD <-> x <-> y <-> z <-> D\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass CyclicDoublyList(ListBase):\n    def __init__(self):\n        self.clear()\n\n    def __iter__(self):\n        node = self.__dummy[2]\n\n        while node is not self.__dummy:\n            obj, _, nxt = node\n            yield obj\n            node = nxt\n\n    def set(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        target = self._get_node(index)\n        target[0] = obj\n        return obj\n\n    def get(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        return self._get_node(index)[0]\n\n    def add(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: void\n        \"\"\"\n        if not self._check_index(index):\n            index = -1\n\n        target = self._get_node(index)\n        if index < 0:\n            node = self._new_node(obj, target, target[2])\n            target[2][1] = node\n            target[2] = node\n        else:\n            node = self._new_node(obj, target[1], target)\n            target[1][2] = node\n            target[1] = node\n\n        self.__size += 1\n\n    def add_all(self, objs, index=-1):\n        \"\"\"\n        :type objs: Iterable\n        :type index: int\n        :rtype: void\n        \"\"\"\n        super(CyclicDoublyList, self).add_all(objs, index)\n\n        if not self._check_index(index):\n            index = -1\n\n        dummy = tail = self._new_node(None)\n        for obj in objs:\n            tail[2] = self._new_node(obj, tail)\n            tail = tail[2]\n\n        target = self._get_node(index)\n        if index < 0:\n            dummy[2][1] = target\n            tail[2] = target[2]\n            target[2][1] = tail\n            target[2] = dummy[2]\n        else:\n            dummy[2][1] = target[1]\n            tail[2] = target\n            target[1][2] = dummy[2]\n            target[1] = tail\n\n        self.__size += len(objs)\n\n    def remove(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        obj, pre, nxt = self._get_node(index)\n        pre[2] = nxt\n        nxt[1] = pre\n\n        self.__size -= 1\n        return obj\n\n    def index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        i = 0\n        node = self.__dummy[2]\n\n        while node is not self.__dummy:\n            if node[0] is obj:\n                return i\n            node = node[2]\n            i += 1\n\n        return -1\n\n    def last_index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        i = 1\n        node = self.__dummy[1]\n\n        while node is not self.__dummy:\n            if node[0] is obj:\n                return i\n            node = node[1]\n            i += 1\n\n        return -1\n\n    def clear(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        dummy = []\n        dummy[:] = self._new_node(None, dummy, dummy)\n        self.__dummy = dummy\n        self.__size = 0\n\n    def clone(self):\n        \"\"\"\n        :rtype: LinkedList\n        \"\"\"\n        pass\n\n    def sort(self, key=None):\n        \"\"\"\n        :type key: function\n        :rtype: void\n        \"\"\"\n        pass\n\n    def _get_size(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.__size\n\n    def _get_node(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: ListNode\n        \"\"\"\n        node = None\n\n        if index < 0:\n            node = self.__dummy\n            while index != 0:\n                index += 1\n                node = node[1]\n        else:\n            node = self.__dummy[2]\n            while index != 0:\n                index -= 1\n                node = node[2]\n\n        return node\n\n    def _new_node(self, obj, pre=None, nxt=None):\n        return [obj, pre, nxt]\n"
  },
  {
    "path": "topic/linked_list/python/cyclic_list.py",
    "content": "\"\"\"\nD --> x --> y --> z --> D\n\nTODO: merge `_get_node`, `_get_prev_node`\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass CyclicList(ListBase):\n    def __init__(self):\n        self.clear()\n\n    def __iter__(self):\n        node = self.__dummy[1]\n\n        while node is not self.__dummy:\n            obj, nxt = node\n            yield obj\n            node = nxt\n\n    def set(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        target = self._get_node(index)\n        target[0] = obj\n        return obj\n\n    def get(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        return self._get_node(index)[0]\n\n    def add(self, obj, index=-1):\n        \"\"\"\n        :type obj: any\n        :type index: int\n        :rtype: void\n        \"\"\"\n        if not self._check_index(index):\n            index = -1\n\n        target = None\n\n        if index < 0:\n            target = self._get_node(index)\n        else:\n            target = self._get_prev_node(index)\n\n        node = self._new_node(obj, target[1])\n        target[1] = node\n\n        self.__size += 1\n\n    def add_all(self, objs, index=-1):\n        \"\"\"\n        :type objs: Iterable\n        :type index: int\n        :rtype: void\n        \"\"\"\n        super(CyclicList, self).add_all(objs, index)\n\n        if not self._check_index(index):\n            index = -1\n\n        dummy = tail = self._new_node(None)\n        for obj in objs:\n            tail[1] = self._new_node(obj)\n            tail = tail[1]\n\n        target = None\n\n        if index < 0:\n            target = self._get_node(index)\n        else:\n            target = self._get_prev_node(index)\n\n        tail[1] = target[1]\n        target[1] = dummy[1]\n\n        self.__size += len(objs)\n\n    def remove(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: any\n        \"\"\"\n        self._check_index(index, raise_error=True)\n        node = self._get_prev_node(index)\n        obj = node[1][0]\n        node[1] = node[1][1]\n\n        self.__size -= 1\n        return obj\n\n    def index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        i = 0\n        node = self.__dummy[1]\n\n        while node is not self.__dummy:\n            if node[0] is obj:\n                return i\n            node = node[1]\n            i += 1\n\n        return -1\n\n    def last_index(self, obj):\n        \"\"\"\n        :type obj: any\n        :rtype: int\n\n        return -1 if not found\n        \"\"\"\n        head = node = self.__dummy[1]\n\n        while node[0] is not obj:\n            if node[1] is head:\n                return -1\n\n            node = node[1]\n\n        i = 0\n\n        while node[1] is not head:\n            node = node[1]\n            i += 1\n\n        return i\n\n    def clear(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        dummy = []\n        dummy[:] = self._new_node(None, dummy)\n        self.__dummy = dummy\n        self.__size = 0\n\n    def clone(self):\n        \"\"\"\n        :rtype: LinkedList\n        \"\"\"\n        pass\n\n    def sort(self, key=None):\n        \"\"\"\n        :type key: function\n        :rtype: void\n        \"\"\"\n        pass\n\n    def _get_size(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.__size\n\n    def _get_node(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: ListNode\n        \"\"\"\n        head = slow = self.__dummy[1]\n\n        if index < 0:\n            fast = head\n            while index != 0:\n                index += 1\n                fast = fast[1]\n            while fast[1] is not head:\n                slow = slow[1]\n                fast = fast[1]\n        else:\n            while index != 0:\n                index -= 1\n                slow = slow[1]\n\n        return slow\n\n    def _get_prev_node(self, index=-1):\n        \"\"\"\n        :type index: int\n        :rtype: ListNode\n\n        This method may return dummy\n        \"\"\"\n        dummy = slow = self.__dummy\n\n        if index < 0:\n            fast = dummy\n            while index != 0:\n                index += 1\n                fast = fast[1]\n            while fast[1] is not dummy:\n                slow = slow[1]\n                fast = fast[1]\n        else:\n            while index != 0:\n                index -= 1\n                slow = slow[1]\n\n        return slow\n\n    def _new_node(self, obj, nxt=None):\n        return [obj, nxt]\n"
  },
  {
    "path": "topic/linked_list/python/dummy_tail_doubly_list.py",
    "content": "\"\"\"\n                  t\nD <-> x <-> y <-> z\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass DummyTailDoublyList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/linked_list/python/dummy_tail_list.py",
    "content": "\"\"\"\n                  t\nD --> x --> y --> z\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass DummyTailList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/linked_list/python/head_tail_doubly_list.py",
    "content": "\"\"\"\nh           t\nx <-> y <-> z\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass HeadTailDoublyList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/linked_list/python/head_tail_list.py",
    "content": "\"\"\"\nh           t\nx --> y --> z\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass HeadTailList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/linked_list/python/linked_list__test.py",
    "content": "from _test.python import *\nfrom linked_list.python import *\n\n\nclass TestLinkedList(TestBase):\n    def _get_instance(self, LinkedList):\n        ll = LinkedList()\n\n        for i in range(10):\n            ll.add(i)\n\n        self.assertEqual(\n            ','.join([str(i) for i in ll]),\n            '0,1,2,3,4,5,6,7,8,9'\n        )\n\n        return ll\n\n    def _test_set(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        for i, val in (\n            (0, 11),\n            (3, 12),\n            (9, 15),\n            (-1, 21),\n            (-5, 25),\n            (-10, 29),\n        ):\n            self.assertEqual(ll.set(val, i), val)\n            self.assertEqual(ll.get(i), val)\n\n        with self.assertRaises(IndexError):\n            ll.set(31, 10)\n            ll.set(31, 11)\n            ll.set(31, -11)\n            ll.set(31, -12)\n\n    def _test_get(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        with self.assertRaises(IndexError):\n            ll.get(10)\n            ll.get(11)\n            ll.get(15)\n            ll.get(-11)\n            ll.get(-15)\n\n        self.assertEqual(ll.get(0), 0)\n        self.assertEqual(ll.get(5), 5)\n        self.assertEqual(ll.get(9), 9)\n\n        self.assertEqual(ll.get(-1), 9)\n        self.assertEqual(ll.get(-3), 7)\n        self.assertEqual(ll.get(-6), 4)\n        self.assertEqual(ll.get(-10), 0)\n\n    def _test_add(self, LinkedList):\n        ll = LinkedList()\n\n        self.assertEqual(len(ll), 0)\n\n        i = 0\n        for c in 'abcdefg':\n            self.assertIsNone(ll.add(c))\n            self.assertEqual(len(ll), i + 1)\n            self.assertEqual(ll.get(i), c)\n            i += 1\n\n        for c in range(-1, -10, -1):\n            self.assertIsNone(ll.add(c, c))\n            self.assertEqual(len(ll), i + 1)\n            self.assertEqual(ll.get(c), c)\n            i += 1\n\n        ll.add('Tail_A', -50)\n        self.assertEqual(ll.get(-1), 'Tail_A')\n\n        ll.add('Tail_B', 50)\n        self.assertEqual(ll.get(-1), 'Tail_B')\n\n    def _test_add_all(self, LinkedList):\n        ll = LinkedList()\n\n        self.assertEqual(len(ll), 0)\n\n        with self.assertRaises(ValueError):\n            ll.add_all(None)\n            ll.add_all(123)\n\n        self.assertIsNone(ll.add_all([i for i in range(5)]))\n        self.assertEqual(len(ll), 5)\n        self.assertEqual(\n            ','.join([str(i) for i in ll]),\n            '0,1,2,3,4'\n        )\n\n        self.assertIsNone(ll.add_all([i for i in range(5, 10)], -3))\n        self.assertEqual(len(ll), 10)\n        self.assertEqual(\n            ','.join([str(i) for i in ll]),\n            '0,1,2,5,6,7,8,9,3,4'\n        )\n\n        ll.add_all('Tail_A', -50)\n        self.assertEqual(ll.get(-1), 'A')\n\n        ll.add_all('Tail_B', 50)\n        self.assertEqual(ll.get(-1), 'B')\n\n    def _test_remove(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        self.assertEqual(len(ll), 10)\n\n        with self.assertRaises(IndexError):\n            ll.remove(10)\n            ll.remove(15)\n            ll.remove(-11)\n            ll.remove(-15)\n\n        for i in range(2, -1, -1):\n            self.assertEqual(ll.remove(i), i)\n            self.assertEqual(len(ll), 7 + i)\n\n        for i in range(2, 0, -1):\n            self.assertEqual(ll.remove(-i), 10 - i)\n            self.assertEqual(len(ll), 4 + i)\n\n        with self.assertRaises(IndexError):\n            ll.remove(6)\n            ll.remove(-6)\n\n    def _test_contains(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        self.assertTrue(ll.contains(0))\n        self.assertTrue(ll.contains(3))\n        self.assertTrue(ll.contains(9))\n\n        self.assertFalse(ll.contains(-1))\n        self.assertFalse(ll.contains(-5))\n        self.assertFalse(ll.contains(10))\n        self.assertFalse(ll.contains(15))\n\n    def _test_index(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        for i in range(10):\n            self.assertEqual(ll.index(i), i)\n\n    def _test_last_index(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        for i in range(10):\n            self.assertEqual(ll.last_index(i), 10 - i)\n\n    def _test_clear(self, LinkedList):\n        ll = self._get_instance(LinkedList)\n\n        self.assertEqual(len(ll), 10)\n\n        ll.clear()\n\n        self.assertEqual(len(ll), 0)\n\n    def _test_clone(self, LinkedList):\n        pass\n\n    def _test_sort(self, LinkedList):\n        pass\n\n    def _run_list_test(self, LinkedList):\n        self._test_set(LinkedList)\n        self._test_get(LinkedList)\n        self._test_add(LinkedList)\n        self._test_add_all(LinkedList)\n        self._test_remove(LinkedList)\n        self._test_contains(LinkedList)\n        self._test_index(LinkedList)\n        self._test_last_index(LinkedList)\n        self._test_clear(LinkedList)\n        self._test_clone(LinkedList)\n        self._test_sort(LinkedList)\n\n    def test_cyclic_list(self):\n        self._run_list_test(CyclicList)\n\n    def test_cyclic_doubly_list(self):\n        self._run_list_test(CyclicDoublyList)\n\n    # def test_dummy_tail_list(self):\n    #     self._run_list_test(DummyTailList)\n\n    # def test_dummy_tail_doubly_list(self):\n    #     self._run_list_test(DummyTailDoublyList)\n\n    # def test_head_tail_list(self):\n    #     self._run_list_test(HeadTailList)\n\n    # def test_head_tail_doubly_list(self):\n    #     self._run_list_test(HeadTailDoublyList)\n\n    # def test_two_dummy_list(self):\n    #     self._run_list_test(TwoDummyList)\n\n    # def test_two_dummy_doubly_list(self):\n    #     self._run_list_test(TwoDummyDoublyList)\n"
  },
  {
    "path": "topic/linked_list/python/two_dummy_doubly_list.py",
    "content": "\"\"\"\nD <-> x <-> y <-> z <-> d\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass TwoDummyDoublyList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/linked_list/python/two_dummy_list.py",
    "content": "\"\"\"\nD --> x --> y --> z <-- d\n\"\"\"\nfrom linked_list.python._helper import *\n\n\nclass TwoDummyList(ListBase):\n    pass\n"
  },
  {
    "path": "topic/problem_set/subarray_sum.md",
    "content": "## Differences\n\n`leetcode/209_minimum_size_subarray_sum.py`\n\n- elements is non-negative\n- sum >= k\n- find min length\n\n`leetcode/325_maximum_size_subarray_sum_equals_k.py`\n\n- elements may be negative\n- sum == k\n- find max length\n\n`leetcode/560_subarray_sum_equals_k.py`\n\n- elements may be negative\n- sum == k\n- count how many subarrays\n\n`leetcode/862_shortest_subarray_with_sum_at_least_k.py`\n\n- elements may be negative\n- sum >= k\n- find min length\n\n## Solutions\n\n- Non-negative => Two Pointers\n- Negative => Prefix Sum\n"
  },
  {
    "path": "topic/problem_set/substring_with_distinct_characters.md",
    "content": "- minimum length:\n\n    ```\n    while cnt == k:\n        # reduce window size if possible\n        # and record it\n    ```\n\n- maximum length:\n\n    ```\n    while cnt > k:\n        # to evict invalid start\n\n    # it's valid here, so record the maximum window size\n    ```\n"
  },
  {
    "path": "topic/range_query/python/__init__.py",
    "content": ""
  },
  {
    "path": "topic/range_query/python/_helper.py",
    "content": ""
  },
  {
    "path": "topic/range_query/python/binary_indexed_tree.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/range_query/python/interval_tree.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/range_query/python/prefix_sum.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/range_query/python/range_tree.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/range_query/python/segment_tree.py",
    "content": "# TODO\n"
  },
  {
    "path": "topic/searching/binary_search.md",
    "content": "Binary search\n======\n\n```python\n>>> arr = [True, True, True, True, False, False]\n>>> left, mid, right = 0, 0, len(arr) - 1\n\n# to prevent dead cycle\n>>> while left + 1 < right:\n...\n...     # to avoid int overflow, but it could be ignored in `Python 3`\n...     mid = left + (right - left) // 2\n...\n...     if arr[mid]:\n...         left = mid\n...     else:\n...         right = mid\n\n# check again the end point, and fetch what we need\n>>> left if arr[left] else right\n3\n```\n"
  },
  {
    "path": "topic/searching/python/__init__.py",
    "content": ""
  },
  {
    "path": "topic/searching/python/_helper.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass SearchBase(ABC):\n    @classmethod\n    @abstractmethod\n    def search(cls, iterable, val):\n        \"\"\"\n        :type iterable: Iterable\n        :type val: any\n        :rtype: int\n        \"\"\"\n        pass\n"
  },
  {
    "path": "topic/sorting/python/__init__.py",
    "content": "from sorting.python.quick_sort import QuickSort\nfrom sorting.python.merge_sort import MergeSort\n"
  },
  {
    "path": "topic/sorting/python/_helper.py",
    "content": "from abc import ABC, abstractmethod\nimport collections\n\n\nclass SortBase(ABC):\n    @classmethod\n    @abstractmethod\n    def sort(cls, iterable):\n        \"\"\"\n        :type iterable: Iterable\n        :rtype: list\n        \"\"\"\n        pass\n\n    @staticmethod\n    def _is_valid_payload(iterable):\n        \"\"\"\n        :type iterable: Iterable\n        :rtype: bool\n        \"\"\"\n        return isinstance(iterable, collections.Iterable)\n"
  },
  {
    "path": "topic/sorting/python/merge_sort.py",
    "content": "from sorting.python._helper import *\n\n\nclass MergeSort(SortBase):\n    @classmethod\n    def sort(cls, iterable):\n        \"\"\"\n        :type iterable: Iterable\n        :rtype: list\n        \"\"\"\n        if not cls._is_valid_payload(iterable):\n            return []\n\n        res = list(iterable)\n        n = len(iterable)\n        cls._divide_conquer(res, 0, n - 1, [None] * n)\n        return res\n\n    @classmethod\n    def _divide_conquer(cls, arr, start, end, tmp):\n        if start >= end:\n            return\n\n        mid = (start + end) // 2\n        left, right = start, mid + 1\n        cls._divide_conquer(arr, left, mid, tmp)\n        cls._divide_conquer(arr, right, end, tmp)\n\n        idx = start\n\n        while left <= mid and right <= end:\n            if arr[left] < arr[right]:\n                tmp[idx] = arr[left]\n                left += 1\n            else:\n                tmp[idx] = arr[right]\n                right += 1\n            idx += 1\n\n        while left <= mid:\n            tmp[idx] = arr[left]\n            left += 1\n            idx += 1\n\n        while right <= end:\n            tmp[idx] = arr[right]\n            right += 1\n            idx += 1\n\n        for idx in range(start, end + 1):\n            arr[idx] = tmp[idx]\n"
  },
  {
    "path": "topic/sorting/python/quick_sort.py",
    "content": "from sorting.python._helper import *\n\n\nclass QuickSort(SortBase):\n    \"\"\"\n    remember to save pivot value in advance\n    since the array is changing all the time\n    \"\"\"\n\n    @classmethod\n    def sort(cls, iterable):\n        \"\"\"\n        :type iterable: Iterable\n        :rtype: list\n        \"\"\"\n        if not cls._is_valid_payload(iterable):\n            return []\n\n        res = list(iterable)\n        n = len(iterable)\n        cls._divide_conquer(res, 0, n - 1)\n        return res\n\n    @classmethod\n    def _divide_conquer(cls, arr, start, end):\n        if start >= end:\n            return\n\n        left, right = start, end\n        pivot = arr[(start + end) // 2]\n\n        while left <= right:\n            while left <= right and arr[left] < pivot:\n                left += 1\n            while left <= right and arr[right] > pivot:\n                right -= 1\n\n            if left <= right:\n                arr[left], arr[right] = arr[right], arr[left]\n                left += 1\n                right -= 1\n\n        cls._divide_conquer(arr, start, right)\n        cls._divide_conquer(arr, left, end)\n"
  },
  {
    "path": "topic/sorting/python/sorting__test.py",
    "content": "from _test.python import *\nfrom sorting.python import *\n\n\nclass TestSorting(TestBase):\n    CASES = (\n        (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),\n        (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),\n        (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),\n        (1, 0, 0, 0, -1, -1, -1, 0, 1, -1),\n        (-2, -5, 3, 7, 6, 6, 0, -9, 7, 2),\n        (-6, -3, -9, -1, 0, 2, 2, 8, 6),\n        (18, 3, 18, 2, 15, 0, -12, -10, -12, -3),\n        (-4, -18, -13, -10, -10, 0, 13, 5, 1, 1),\n        (70, 91, 92, -42, -4, 13, -12, -94, -56, -70, 34, -97, 58, -14, -75),\n    )\n\n    def _run_sorting_test(self, Sort):\n        for case in self.CASES:\n            a = list(case)\n            b = Sort.sort(a)\n            c = sorted(a)\n\n            self.assertIsNot(a, b)\n            self.assertEqual(b, c)\n\n    def test_quick_sort(self):\n        self._run_sorting_test(QuickSort)\n\n    def test_merge_sort(self):\n        self._run_sorting_test(MergeSort)\n"
  },
  {
    "path": "topic/system_design/latency.md",
    "content": "Latency Comparison Numbers\n======\n\nSourced from [Latency Numbers Every Programmer Should Know | GitHub](https://gist.github.com/jboner/2841832)\n\n| Item                               |          ns |      us |   ms | more                        |\n| :--------------------------------- | ----------: | ------: | ---: | :-------------------------- |\n| L1 cache reference                 |         0.5 |         |      |                             |\n| Branch mispredict                  |           5 |         |      |                             |\n| L2 cache reference                 |           7 |         |      | 14x L1 cache                |\n| Mutex lock/unlock                  |          25 |         |      |                             |\n| Main memory reference              |         100 |         |      | 20x L2 cache, 200x L1 cache |\n| Compress 1K bytes with Zippy       |       3,000 |       3 |      |                             |\n| Send 1K bytes over 1 Gbps network  |      10,000 |      10 |      |                             |\n| Read 4K randomly from SSD*         |     150,000 |     150 |      | ~1GB/sec SSD                |\n| Read 1 MB sequentially from memory |     250,000 |     250 |      |                             |\n| Round trip within same datacenter  |     500,000 |     500 |      |                             |\n| Read 1 MB sequentially from SSD*   |   1,000,000 |   1,000 |    1 | ~1GB/sec SSD, 4X memory     |\n| Disk seek                          |  10,000,000 |  10,000 |   10 | 20x datacenter roundtrip    |\n| Read 1 MB sequentially from disk   |  20,000,000 |  20,000 |   20 | 80x memory, 20X SSD         |\n| Send packet CA->Netherlands->CA    | 150,000,000 | 150,000 |  150 |                             |\n\nnote that,\n\n- 1 ns = 10^-9 seconds\n- 1 us = 10^-6 seconds = 1,000 ns\n- 1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns\n"
  },
  {
    "path": "topic/traversal/python/__init__.py",
    "content": "from traversal.python.recursive_traversal import RecursiveTraversal\nfrom traversal.python.iterative_traversal import IterativeTraversal\nfrom traversal.python.morris_traversal import MorrisTraversal\n"
  },
  {
    "path": "topic/traversal/python/_helper.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass TraversalBase(ABC):\n    @classmethod\n    @abstractmethod\n    def preorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def inorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def postorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        pass\n"
  },
  {
    "path": "topic/traversal/python/binary_tree_traversal__test.py",
    "content": "from _test.python import *\nfrom traversal.python import *\nfrom tree.python import BinaryTree\n\n\nclass TestBinaryTreeTraversal(TestBase):\n    CASES = {\n        '{1,2,3,4,#,#,5,#,6,#,#,7,8}': {\n            'preorder': '1,2,4,6,7,8,3,5',\n            'inorder': '4,7,6,8,2,1,3,5',\n            'postorder': '7,8,6,4,2,5,3,1',\n        },\n        '{1,#,2,#,3,#,4,#,5,#,6,#,7}': {\n            'preorder': '1,2,3,4,5,6,7',\n            'inorder': '1,2,3,4,5,6,7',\n            'postorder': '7,6,5,4,3,2,1',\n        },\n    }\n\n    trees = None\n\n    def setUp(self):\n        super(TestBinaryTreeTraversal, self).setUp()\n\n        self.trees = {\n            case: BinaryTree.deserialize(case)\n            for case in self.CASES\n        }\n\n    def _run_traversal_test(self, Traversal):\n        for traverse in (\n            Traversal.preorder_traverse,\n            Traversal.inorder_traverse,\n            Traversal.postorder_traverse,\n        ):\n            for i, o in self.CASES.items():\n                res = []\n                traverse(\n                    self.trees[i],\n                    callback=lambda val: res.append(str(val))\n                )\n\n                key = traverse.__name__.replace('_traverse', '')\n                self.assertEqual(o[key], ','.join(res))\n\n    def test_recursive_traversal(self):\n        self._run_traversal_test(RecursiveTraversal)\n\n    def test_iterative_traversal(self):\n        self._run_traversal_test(IterativeTraversal)\n\n    def test_morris_traversal(self):\n        self._run_traversal_test(MorrisTraversal)\n"
  },
  {
    "path": "topic/traversal/python/iterative_traversal.py",
    "content": "from traversal.python._helper import *\n\n\nclass IterativeTraversal(TraversalBase):\n    @classmethod\n    def preorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        node = root\n        stack = []\n\n        while node or stack:\n            while node:\n                callback(node.val)\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n            node = node.right\n\n    @classmethod\n    def inorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        node = root\n        stack = []\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack.pop()\n            callback(node.val)\n            node = node.right\n\n    @classmethod\n    def postorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        node = last_visit = root\n        stack = []\n\n        while node or stack:\n            while node:\n                stack.append(node)\n                node = node.left\n\n            node = stack[-1]\n\n            if node.right and last_visit is not node.right:\n                node = node.right\n            else:\n                stack.pop()\n\n                callback(node.val)\n                last_visit = node\n                node = None\n"
  },
  {
    "path": "topic/traversal/python/morris_traversal.py",
    "content": "from traversal.python._helper import *\nfrom tree.python import TreeNode\n\n\nclass MorrisTraversal(TraversalBase):\n    \"\"\"\n    REF: https://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html\n    \"\"\"\n\n    @classmethod\n    def preorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        node = None\n\n        while root:\n            if not root.left:\n                callback(root.val)\n                root = root.right\n                continue\n\n            node = root.left\n\n            while node.right and node.right is not root:\n                node = node.right\n\n            if node.right:\n                node.right = None\n                root = root.right\n            else:\n                callback(root.val)\n                node.right = root\n                root = root.left\n\n    @classmethod\n    def inorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        node = None\n\n        while root:\n            if not root.left:\n                callback(root.val)\n                root = root.right\n                continue\n\n            node = root.left\n\n            while node.right and node.right is not root:\n                node = node.right\n\n            if node.right:\n                callback(root.val)\n                node.right = None\n                root = root.right\n            else:\n                node.right = root\n                root = root.left\n\n    @classmethod\n    def postorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        dummy = TreeNode(0)\n        dummy.left = root\n\n        root = dummy\n        node = None\n\n        while root:\n            if not root.left:\n                root = root.right\n                continue\n\n            node = root.left\n\n            while node.right and node.right is not root:\n                node = node.right\n\n            if node.right:\n                cls._postorder_reverse_visit(root.left, node, callback=callback)\n                node.right = None\n                root = root.right\n            else:\n                node.right = root\n                root = root.left\n\n    @classmethod\n    def _postorder_reverse_visit(cls, from_node, to_node, callback):\n        cls._postorder_reverse(from_node, to_node)\n\n        node = to_node\n        callback(node.val)\n\n        while node and node is not from_node:\n            node = node.right\n            callback(node.val)\n\n        cls._postorder_reverse(to_node, from_node)\n\n    @classmethod\n    def _postorder_reverse(cls, from_node, to_node):\n        root = from_node\n        node = from_node.right\n        nxt = None\n\n        while root is not to_node:\n            nxt = node.right\n            node.right = root\n            root = node\n            node = nxt\n"
  },
  {
    "path": "topic/traversal/python/recursive_traversal.py",
    "content": "from traversal.python._helper import *\n\n\nclass RecursiveTraversal(TraversalBase):\n    @classmethod\n    def preorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        callback(root.val)\n        cls.preorder_traverse(root.left, callback=callback)\n        cls.preorder_traverse(root.right, callback=callback)\n\n    @classmethod\n    def inorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        cls.inorder_traverse(root.left, callback=callback)\n        callback(root.val)\n        cls.inorder_traverse(root.right, callback=callback)\n\n    @classmethod\n    def postorder_traverse(cls, root, callback=None):\n        \"\"\"\n        :type root: TreeNode\n        :type callback: function\n        :rtype: void\n        \"\"\"\n        if not root:\n            return\n\n        cls.postorder_traverse(root.left, callback=callback)\n        cls.postorder_traverse(root.right, callback=callback)\n        callback(root.val)\n"
  },
  {
    "path": "topic/tree/binary_tree.md",
    "content": "Binary Tree\n======\n\n## Binary Tree\n\n```\nTODO\n```\n\n## Binary Search Tree\n\n- the value of left child must be less than (<) the root node\n- the value of right child must be great than or equal to (>=) the root node\n- traversal BST by in-order, got a non-descending sequence (A[i+1] >= A[i])\n"
  },
  {
    "path": "topic/tree/python/__init__.py",
    "content": "from tree.python.trie import *\nfrom tree.python.binary_tree import *\n"
  },
  {
    "path": "topic/tree/python/_helper.py",
    "content": ""
  },
  {
    "path": "topic/tree/python/binary_tree.py",
    "content": "class TreeNode:\n    def __init__(self, val):\n        self.val = val\n        self.left = self.right = None\n\n\nclass BinaryTree:\n    EMPTY = '#'\n    TMPL = '{{{}}}'  # {{, }} is to escape brackets\n\n    @classmethod\n    def serialize(cls, root):\n        \"\"\"Encodes a tree to a single string.\n        :type root: TreeNode\n        :rtype: str\n        \"\"\"\n        if not root:\n            return cls.TMPL.format('')\n\n        values = []\n        queue = [root]\n\n        for node in queue:\n            if not node:\n                values.append(cls.EMPTY)\n                continue\n\n            values.append(str(node.val))\n            queue.append(node.left)\n            queue.append(node.right)\n\n        while values[-1] == cls.EMPTY:\n            values.pop()\n\n        return cls.TMPL.format(','.join(values))\n\n    @classmethod\n    def deserialize(cls, data):\n        \"\"\"Decodes your encoded data to tree.\n        :type data: str\n        :rtype: TreeNode\n        \"\"\"\n        if any((\n            not data,\n            len(data) < 3,\n            data[0] != '{',\n            data[-1] != '}',\n            data[1] in (cls.EMPTY, ','),\n        )):\n            return\n\n        values = data[1:-1].split(',')\n        i = 0\n        root = TreeNode(int(values[i]))\n        queue = [root]\n\n        for node in queue:\n            for branch in ('left', 'right'):\n                i += 1\n\n                if i >= len(values):\n                    break\n                if values[i] == cls.EMPTY:\n                    continue\n\n                setattr(node, branch, TreeNode(int(values[i])))\n                queue.append(getattr(node, branch))\n\n        return root\n"
  },
  {
    "path": "topic/tree/python/binary_tree__test.py",
    "content": "from _test.python import *\nfrom tree.python import BinaryTree\n\n\nclass TestBinaryTree(TestBase):\n    def test_serialization(self):\n        case = '{1,2,3,4,#,#,5,#,6,#,#,7,8}'\n        tree = BinaryTree.deserialize(case)\n\n        self.assertIsNotNone(tree)\n        self.assertEqual(\n            case,\n            BinaryTree.serialize(tree)\n        )\n\n        left = right = None\n\n        # level 1\n        self.assertEqual(1, tree.val)\n\n        # level 2\n        left, right = tree.left, tree.right\n        self.assertEqual(2, left.val)\n        self.assertEqual(3, right.val)\n\n        # level 3\n        self.assertIs(None, left.right)\n        self.assertIs(None, right.left)\n        left, right = left.left, right.right\n        self.assertEqual(4, left.val)\n        self.assertEqual(5, right.val)\n\n        # level 4\n        self.assertIs(None, left.left)\n        self.assertIs(None, right.left)\n        self.assertIs(None, right.right)\n        tree = left.right\n        self.assertEqual(6, tree.val)\n\n        # level 5\n        left, right = tree.left, tree.right\n        self.assertEqual(7, left.val)\n        self.assertEqual(8, right.val)\n\n        # empty level\n        self.assertIs(None, left.left)\n        self.assertIs(None, left.right)\n        self.assertIs(None, right.left)\n        self.assertIs(None, right.right)\n"
  },
  {
    "path": "topic/tree/python/trie.py",
    "content": "import collections\n\n\nclass TrieNode:\n    def __init__(self):\n        self.children = collections.defaultdict(TrieNode)\n        self.end_of = None\n\n\nclass Trie:\n    def __init__(self):\n        self.root = TrieNode()\n\n    def __repr__(self):\n        return repr(self.root)\n\n    def put(self, word):\n        if not self._is_str(word):\n            return\n\n        node = self.root\n\n        for char in word:\n            node = node.children[char]\n\n        node.end_of = word\n\n    def has_word(self, word):\n        if not self._is_str(word):\n            return False\n\n        return self._search(word) is word\n\n    def has_prefix(self, word):\n        if not self._is_str(word):\n            return False\n\n        return self._search(word) is not False\n\n    def get_node(self, char, node=None):\n        if not node:\n            node = self.root\n\n        if char in node.children:\n            return node.children[char]\n\n    def _search(self, word):\n        node = self.root\n\n        if not word and node.end_of is None:\n            return False\n\n        for char in word:\n            if char not in node.children:\n                return False\n\n            node = node.children[char]\n\n        return node.end_of\n\n    def _is_str(self, word):\n        return isinstance(word, (str, bytes))\n"
  },
  {
    "path": "topic/tree/python/trie__test.py",
    "content": "from _test.python import *\nfrom tree.python import Trie\n\n\nclass TestTrie(TestBase):\n    def test_init(self):\n        trie = Trie()\n\n        for attr, default_val in (\n            ('children', {}),\n            ('end_of', None),\n        ):\n            self.assertTrue(hasattr(trie.root, attr))\n            self.assertEqual(getattr(trie.root, attr), default_val)\n\n    def test_put(self):\n        trie = Trie()\n        node = None\n        TEST_WORD = 'aabbccdefg'\n\n        trie.put(TEST_WORD)\n\n        for char in TEST_WORD:\n            node = trie.get_node(char, node)\n            if node.end_of == TEST_WORD:\n                self.assertTrue(len(node.children) == 0)\n            else:\n                self.assertTrue(len(node.children) == 1)\n\n        # for case in empty string ''\n        self.assertEqual(trie.root.end_of, None)\n        trie.put('')\n        self.assertEqual(trie.root.end_of, '')\n\n    def test_has_word_or_prefix(self):\n        trie = Trie()\n\n        trie.put('abc')\n\n        self.assertTrue(trie.has_word('abc'))\n        self.assertTrue(trie.has_prefix('a'))\n        self.assertTrue(trie.has_prefix('ab'))\n        self.assertTrue(trie.has_prefix('abc'))\n        self.assertFalse(trie.has_word(''))\n        self.assertFalse(trie.has_word('abd'))\n        self.assertFalse(trie.has_word('abcd'))\n        self.assertFalse(trie.has_prefix('abcd'))\n\n        node = None\n        trie.put('abd')\n\n        for char in 'abd':\n            node = trie.get_node(char, node)\n            if char == 'a':\n                self.assertTrue(len(node.children) == 1)\n            elif char == 'b':\n                self.assertTrue(len(node.children) == 2)\n            elif node.end_of == 'abd':\n                self.assertTrue(len(node.children) == 0)\n            else:\n                # should not visit here\n                self.assertTrue(False)\n\n        # for case in empty string ''\n        self.assertEqual(trie.root.end_of, None)\n        self.assertFalse(trie.has_word(''))\n        self.assertFalse(trie.has_prefix(''))\n        trie.put('')\n        self.assertEqual(trie.root.end_of, '')\n        self.assertTrue(trie.has_word(''))\n        self.assertTrue(trie.has_prefix(''))\n\n    def test_invalid_put(self):\n        trie = Trie()\n\n        for word, cnt, end_of in (\n            (None, 0, None),\n            ({}, 0, None),\n            ({'a': 1}, 0, None),\n            ([], 0, None),\n            ([1, 2, 3], 0, None),\n            ('a', 1, None),\n            (u'b', 2, None),\n            (b'c', 3, None),\n            ('', 3, ''),\n        ):\n            trie.put(word)\n            self.assertTrue(len(trie.root.children) == cnt)\n            self.assertTrue(trie.root.end_of == end_of)\n"
  }
]