{"id":13688426,"url":"https://github.com/cy69855522/Shortest-LeetCode-Python-Solutions","last_synced_at":"2025-05-01T19:31:02.281Z","repository":{"id":37451008,"uuid":"182100453","full_name":"cy69855522/Shortest-LeetCode-Python-Solutions","owner":"cy69855522","description":"  Leet Code 刷题笔记 - - 不求最快最省，但求最短最优雅，Shorter is better here.","archived":false,"fork":false,"pushed_at":"2022-03-02T14:17:46.000Z","size":2107,"stargazers_count":1129,"open_issues_count":1,"forks_count":199,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-04-12T11:55:37.865Z","etag":null,"topics":["elegant","leetcode","leetcode-python","leetcode-solutions","python","python3","shortest"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cy69855522.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-18T14:14:48.000Z","updated_at":"2025-04-09T01:42:30.000Z","dependencies_parsed_at":"2022-08-19T09:11:30.935Z","dependency_job_id":null,"html_url":"https://github.com/cy69855522/Shortest-LeetCode-Python-Solutions","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cy69855522%2FShortest-LeetCode-Python-Solutions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cy69855522%2FShortest-LeetCode-Python-Solutions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cy69855522%2FShortest-LeetCode-Python-Solutions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cy69855522%2FShortest-LeetCode-Python-Solutions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cy69855522","download_url":"https://codeload.github.com/cy69855522/Shortest-LeetCode-Python-Solutions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251932639,"owners_count":21667185,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elegant","leetcode","leetcode-python","leetcode-solutions","python","python3","shortest"],"created_at":"2024-08-02T15:01:13.491Z","updated_at":"2025-05-01T19:31:00.878Z","avatar_url":"https://github.com/cy69855522.png","language":null,"funding_links":[],"categories":["Others"],"sub_categories":[],"readme":"# :snake: Shortest-LeetCode-Python-Solutions\n  Leet Code 刷题笔记 - - 不求最快最省，但求最短最优雅 :herb:，Shorter is better here.\n\n# 前言\n- 项目持续更新中，优先使用 python3，不支持的题目使用 python2 代替，如果您有更短更优雅的解法希望分享的话欢迎联系更新~  [直接发issue 或 fork，记得留下署名和联系方式 :panda_face:] 鉴于追求的主题，此项目收录 1.在代码量(不是行数)上明显优于现有解的最短代码 2.思路更高效的一般解法（作为补充放在首选解之后） [题目自带的代码不计入代码量]\n- 如果您对当前解析有任何疑问，咱们 issue 见~\n- 由于CSDN博客更新需要人工审核比较慢，所以迁移到github上，优先更新github内容。\n- 为了快速找到题目可以按 [**Ctrl键 + F键**] 输入题目序号或名字定位。\n- 欢迎加入**QQ交流群**：902025048 [∷二维码](QR.png) 群内提供更多相关资料~\n# :trophy: 里程碑\n- [:penguin: 腾讯精选练习](https://leetcode-cn.com/problemset/all/?listId=ex0k24j)（50题: 25简单 21中等 4困难） 代码行数 总计：140行 平均：2.8行 [:bookmark_tabs: 题目详情](tencent50.png) :calendar: 2019/05/05\n- 🧬 数据结构\n\t- [🐤 队列 \u0026 栈](#-%E9%98%9F%E5%88%97--%E6%A0%88)（5 章节 32 栏目） 高可读，不含VIP解锁题 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/queue-stack/) :calendar: 2019/05/31\n\t- [🐑 数组和字符串](#-%E6%95%B0%E7%BB%84%E5%92%8C%E5%AD%97%E7%AC%A6%E4%B8%B2)（5 章节 29 栏目） 高可读 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/queue-stack/) :calendar: 2019/06/15\n\t- [🦌 链表](#-%E9%93%BE%E8%A1%A8)（5 章节 26 栏目） 高可读 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/linked-list/197/conclusion/) :calendar: 2019/06/25\n\t- [🦎 哈希表](#-%E5%93%88%E5%B8%8C%E8%A1%A8)（5 章节 35 栏目） 高可读，不含VIP解锁题 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/linked-list/197/conclusion/) :calendar: 2019/07/07\n\t- [🐄 二分查找](#-%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE)（8 章节 30 栏目） 高可读，不含VIP解锁题 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/binary-search/) :calendar: 2019/07/30\n\t- [🦉 二叉树](#-%E4%BA%8C%E5%8F%89%E6%A0%91)（3 章节 16 栏目） 高可读 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/data-structure-binary-tree/) :calendar: 2019/09/21\n\t- [🐦 二叉搜索树](#-%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91)（3 章节 16 栏目） 高可读 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/introduction-to-data-structure-binary-search-tree/) :calendar: 2019/11/15\n\t- [🐈 N叉树](#-n%E5%8F%89%E6%A0%91)（3 章节 7 栏目） 高可读，不含VIP解锁题 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/learn/card/n-ary-tree/) :calendar: 2019/11/17\n- ⏱ [递归 I](#-%E9%80%92%E5%BD%92-i)（5 章节 28 栏目） 高可读 [:bookmark_tabs: 题目详情](https://leetcode-cn.com/explore/featured/card/recursion-i/) :calendar: 2019/11/28\n\n## 推荐\n- 🐱‍👤[Python的算法题公式化套路总结](https://github.com/cy69855522/Python-Algorithm-Formula/blob/main/README.md)\n- 👻[ Leetcode最简C++题解 ](https://github.com/cy69855522/Simplest-LeetCode-Cpp-Solutions)\n- 🎃[ C++清晰题解汇总 ](https://github.com/cy69855522/Clearest-LeetCode-Cpp-Solutions)\n- [🚀 AI Power](https://www.aipower.xyz) 云GPU租借/出租平台：Python是AI的核心，GPU是AI的动力，想要朝AI工程师发展的朋友不妨了解一下~ 现在注册并绑定（参考Github）即可获得高额算力。详情请参考[AI Power指南](https://github.com/cy69855522/AI-Power)\n- 🌟 推荐刷题路线：[**专题探索**](#专题探索) → [腾讯精选50题](https://leetcode-cn.com/problemset/all/?listId=ex0k24j) → [题库解析](#题库解析)\n- [常用技巧总结](常用技巧总结)\n- [隐藏的坑](隐藏的坑)\n\n# 题库解析\n此专栏追求代码的**精简**和**技巧性**，默认已看过题目，🤡 没看过的话点标题可以跳转链接，咱们一起体验炫酷的 Python\n\n\u003cdetails\u003e\n  \u003csummary\u003e点击展开折叠\u003c/summary\u003e\n\t\n## [1. Two Sum 4行](https://leetcode.com/problems/two-sum/)\n```python\nclass Solution:\n    def twoSum(self, nums: List[int], target: int) -\u003e List[int]:\n\td = {}\n\tfor i, n in enumerate(nums): \n\t    if n in d: return [d[n], i]\n\t    d[target-n] = i\n```\n- O(N)时间效率的快速解法，用字典记录 ｛需要的值:当前索引｝\n## [2. Add Two Numbers 5行](https://leetcode.com/problems/add-two-numbers/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def addTwoNumbers(self, l1: ListNode, l2: ListNode, carry=0) -\u003e ListNode:\n        if not (l1 or l2): return ListNode(1) if carry else None\n        l1, l2 = l1 or ListNode(0), l2 or ListNode(0)\n        val = l1.val + l2.val + carry\n        l1.val, l1.next = val % 10, self.addTwoNumbers(l1.next, l2.next, val \u003e 9)\n        return l1\n```\n- int(True) 等于 1\n- None or 7 等于 7\n- 用 carry 记录是否应该进位\n## [3. Longest Substring Without Repeating Characters 3行](https://leetcode.com/problems/longest-substring-without-repeating-characters/)\n```python\nclass Solution:\n    def lengthOfLongestSubstring(self, s: str) -\u003e int:\n        i, r, d = 0, 0, {}\n        for j, c in enumerate(s): i, r, d[c] = max(i, d.get(c, -1) + 1), max(r, j - i), j\n        return max(r, len(s) - i)\n```\n- 双指针滑动窗口\n- i 代表起始位置，r 记录最优解，d 是一个字典，记录所有字符最后出现的位置\n- 每次迭代过程中，遇到遇见过的字符时，i 就会变为那个字符上一次出现位置 + 1，r 记录上一次应该达到的全局最大值，所以最后需要再比较一次\n## [4. Median of Two Sorted Arrays 5行](https://leetcode.com/problems/median-of-two-sorted-arrays/)\n```python\nclass Solution:\n    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -\u003e float:\n        a, b, m = *sorted((nums1, nums2), key=len), (len(nums1) + len(nums2) - 1) // 2\n        self.__class__.__getitem__ = lambda self, i: m-i-1 \u003c 0 or a[i] \u003e= b[m-i-1]\n        i = bisect.bisect_left(self, True, 0, len(a))\n        r = sorted(a[i:i+2] + b[m-i:m-i+2])\n        return (r[0] + r[1 - (len(a) + len(b)) % 2]) / 2\n```\n- 本题思路与官方题解类似，时间复杂度O(log(min(m, n)))，没看过的话建议先大体了解一下\n- python 中 bisect 模块针对的是 list, 如果直接构造 list，时间复杂度为 O(min(m, n))，因此我们修改当前类的魔法方法伪造 list\n- 在一个有序递增数列中，中位数左边的那部分的最大值一定小于或等于右边部分的最小值\n- 如果总数组长度为奇数，m 代表中位数的索引，否则 m 代表用于计算中位数的那两个数字的左边一个。比如输入为[1,2]，[3]，那么m应该为[1,2,3]中位数2的索引1，如果输入为[1,3]，[2,4]，那么m应该为[1,2,3,4]中2的索引1\n- 使用二分搜索找到 m 对应的值在a或b中对应的索引，也就是说，我们要找的中位数或中位数左部应该是 a[i] 或者 b[m-i]\n- bisect.bisect_left 搜索列表中保持列表升序的情况下，True应该插入的位置（从左侧），比如 [F,F,T] 返回 2，[F,F] 返回 2\n- 这里保证 a 是 nums1 和 nums2 中较短的那个，是为了防止二分搜索的时候索引越界\n- sorted返回一个list，假设返回值是 [nums1, nums2]，那么前面加个 * 号就代表取出列表的所有内容，相当于一个迭代器，结果相当于直接写 nums1, nums2\n## [5. Longest Palindromic Substring 5行](https://leetcode.com/problems/longest-palindromic-substring/)\n```python\nclass Solution:\n    def longestPalindrome(self, s: str) -\u003e str:\n        r = ''\n        for i, j in [(i, j) for i in range(len(s)) for j in (0, 1)]:\n            while i \u003e -1 and i + j \u003c len(s) and s[i] == s[i + j]: i, j = i - 1, j + 2\n            r = max(r, s[i + 1:i + j], key=len)\n        return '' if not s else r\n```\n- 遍历字符串的每个索引 i，判断能否以 s[i] 或 s[i:i+j+1] 为中心向往拓展回文字符串\n## [7. Reverse Integer 2行](https://leetcode.com/problems/reverse-integer/)\n\n```python\nclass Solution:\n    def reverse(self, x):\n        r = x // max(1, abs(x)) * int(str(abs(x))[::-1])\n        return r if r.bit_length() \u003c 32 or r == -2**31 else 0\n```\n- x // max(1, abs(x))意味着 0：x为0， 1：x为正， -1：x为负，相当于被废弃的函数cmp\n- [::-1]代表序列反转\n- 2^31 和 -2^31 的比特数为32，其中正负号占用了一位\n- 32位整数范围 [−2^31,  2^31 − 1] 中正数范围小一个是因为0的存在\n## [8. String to Integer (atoi) 1行](https://leetcode.com/problems/string-to-integer-atoi/)\n```python\nclass Solution:\n    def myAtoi(self, s: str) -\u003e int:\n        return max(min(int(*re.findall('^[\\+\\-]?\\d+', s.lstrip())), 2**31 - 1), -2**31)\n```\n- 使用正则表达式 `^：匹配字符串开头，[\\+\\-]：代表一个+字符或-字符，?：前面一个字符可有可无，\\d：一个数字，+：前面一个字符的一个或多个，\\D：一个非数字字符`\n- `max(min(数字, 2**31 - 1), -2**31)` 用来防止结果越界\n## [9. Palindrome Number 1行](https://leetcode.com/problems/palindrome-number/)\n\n```python\nclass Solution:\n    def isPalindrome(self, x: int) -\u003e bool:\n        return (k:=str(x)) == k[::-1]\n```\n不使用字符串的进阶解法：\n\n```python\nclass Solution:\n    def isPalindrome(self, x: int) -\u003e bool:\n        r = list(map(lambda i: int(10**-i * x % 10), range(int(math.log10(x)), -1, -1))) if x \u003e 0 else [0, x]\n        return r == r[::-1]\n```\n- 思路是一样的，这里把整数转成了列表而不是字符串\n- 比如一个整数12321，我想取出百位数可以这么做：12321 * 10^{int(log_{10}12321)} % 10 = 123 % 10 = 3\n## [11. Container With Most Water 3行](https://leetcode.com/problems/container-with-most-water/)\n```python\nclass Solution:\n    def maxArea(self, height: List[int]) -\u003e int:\n        res, l, r = 0, 0, len(height) - 1\n        while l \u003c r: res, l, r = (max(res,  height[l] * (r - l)), l + 1, r) if height[l] \u003c height[r] else (max(res,  height[r] * (r - l)), l, r - 1)\n        return res\n```\n- 双指针 O(N) 解法\n- res：结果，l：容器左壁索引，r：容器右壁索引\n- 如果 height[l] \u003c height[r] 那么 l += 1 否则 r -= 1，说明：如果 height[0] \u003c height[3] 那么(0, 1), (0, 2)对应的容器体积一定小于(0, 3)的，因为此时计算体积的时候高为 height(0)，容器的宽减少而高不增加，面积必然缩小\n## [13. Roman to Integer 2行](https://leetcode.com/problems/roman-to-integer/)\n\n```python\nclass Solution:\n    def romanToInt(self, s: str) -\u003e int:\n        d = {'I':1, 'IV':3, 'V':5, 'IX':8, 'X':10, 'XL':30, 'L':50, 'XC':80, 'C':100, 'CD':300, 'D':500, 'CM':800, 'M':1000}\n        return sum(d.get(s[max(i-1, 0):i+1], d[n]) for i, n in enumerate(s))\n```\n- 构建一个字典记录所有罗马数字子串，注意长度为2的子串记录的值是（实际值-子串内左边罗马数字代表的数值）\n- 这样一来，遍历整个s的时候判断当前位置和前一个位置的两个字符组成的字符串是否在字典内，如果在就记录值，不在就说明当前位置不存在小数字在前面的情况，直接记录当前位置字符对应值\n- 举个例子，遍历经过IV的时候先记录I的对应值1再往前移动一步记录IV的值3，加起来正好是IV的真实值4。max函数在这里是为了防止遍历第一个字符的时候出现[-1:0]的情况\n## [14. Longest Common Prefix 2行](https://leetcode.com/problems/longest-common-prefix/)\n\n```python\nclass Solution:\n    def longestCommonPrefix(self, strs: List[str]) -\u003e str:\n        r = [len(set(c)) == 1 for c in zip(*strs)] + [0]\n        return strs[0][:r.index(0)] if strs else ''\n```\n- 利用好zip和set\n- os 模块有提供一样的函数\n\t```python\n\tclass Solution:\n\t    def longestCommonPrefix(self, strs: List[str]) -\u003e str:\n\t\treturn os.path.commonprefix(strs)\n\t```\n## [15. 3Sum 5行](https://leetcode.com/problems/3sum/)\n```python\nclass Solution:\n    def threeSum(self, nums: List[int]) -\u003e List[List[int]]:\n        nums, r = sorted(nums), set()\n        for i in [i for i in range(len(nums)-2) if i \u003c 1 or nums[i] \u003e nums[i-1]]:\n            d = {-nums[i]-n: j for j, n in enumerate(nums[i + 1:])}\n            r.update([(nums[i], n, -nums[i]-n) for j, n in enumerate(nums[i+1:]) if n in d and d[n] \u003e j])\n        return list(map(list, r))\n```\n- 时间复杂度：O(N^2)\n- 这里 sort 一是为了避免重复，这一点可以体现在我们输出的结果都是升序的，如果不这么做 set 无法排除一些相同结果，而是为了节省计算，防止超时\n- for 循环内部的代码思想同` 第一题 Two Sum`，用字典记录｛需要的值:当前索引｝，如果字典中存在相同的数字，那么将会记录比较大的那个索引，因此可以用`d[n] \u003e i`来避免一个元素重复选择\n- `(nums[i], n, -nums[i]-n)`保证了列表升序\n## [16. 3Sum Closest 7行](https://leetcode.com/problems/3sum-closest/)\n```python\nclass Solution:\n    def threeSumClosest(self, nums: List[int], target: int) -\u003e int:\n        nums, r, end = sorted(nums), float('inf'), len(nums) - 1\n        for c in range(len(nums) - 2):\n            i, j = max(c + 1, bisect.bisect_left(nums, target - nums[end] - nums[c], c + 1, end) - 1), end\n            while r != target and i \u003c j:\n                s = nums[c] + nums[i] + nums[j]\n                r, i, j = min(r, s, key=lambda x: abs(x - target)), i + (s \u003c target), j - (s \u003e target)\n        return r\n```\n- float('inf') = 正无穷\n- 排序，遍历，双指针，O(N^2) 时间复杂度，二分法初始化\n- 排序是为了使用双指针，首先遍历得到索引 c，然后计算 c，左指针 i，右指针 j 对应数字之和，如果大于 target，j 向内移动，否则 i 向内移动\n- i 的初始值不是 c + 1，是为了减少计算量，用二分法得到一个合理的初始值\n## [17. Letter Combinations of a Phone Number 3行](https://leetcode.com/problems/letter-combinations-of-a-phone-number/)\n```python\nclass Solution:\n    def letterCombinations(self, digits: str) -\u003e List[str]:\n        from itertools import product\n        l = '- - abc def ghi jkl mno pqrs tuv wxyz'.split()\n        return [''.join(c) for c in product(*[l[int(i)] for i in digits])] if digits else []\n```\n- 本题相当于求解笛卡尔积\n## [18. 4Sum 5行](https://leetcode.com/problems/4sum/)\n```python\nclass Solution:\n    def fourSum(self, nums: List[int], target: int) -\u003e List[List[int]]:\n        from itertools import combinations as com\n        dic, l = collections.defaultdict(list), [*com(range(len(nums)), 2)]\n        for a, b in l: dic[target - nums[a] - nums[b]].append((a, b))\n        r = [(*ab, c, d) for c, d in l for ab in dic[nums[c] + nums[d]]]\n        return [*set(tuple(sorted(nums[i] for i in t)) for t in r if len(set(t)) == 4)]\n```\n- 思想类似于 2SUM，先得到任意两个数字的和记入字典，然后再获得其余任意俩个数字，看看是否匹配。2个 2SUM 相当于 4SUM。时间复杂度为 O(N^2)\n- 1.用 combination 获得 nums 中任意两个不同索引的组合\n- 2.用字典记录任意两个数字的和，dic =｛除了这两个数字之外还差多少：这俩个数字在 nums 中的索引｝\n- 3.用 r 记录所有满足条件的索引序列，注意此时可能含有重复的索引\n- 4.利用 len + set 保证 a，b，c，d 各不相等，用 set 删除重复的结果\n## [19. Remove Nth Node From End of List 5行](https://leetcode.com/problems/remove-nth-node-from-end-of-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def removeNthFromEnd(self, head: ListNode, n: int) -\u003e ListNode:\n        l = []\n        while head: l, head = l + [head], head.next\n        if n != len(l): l[-n-1].next = l[-n].next\n        del l[-n]\n        return l and l[0]\n```\n- 列表记录整个链表，换成队列记录最后几个可以把空间复杂度压到 O(1)\n## [20. Valid Parentheses 2行](https://leetcode.com/problems/valid-parentheses/)\n\n```python\nclass Solution:\n    def isValid(self, s: str) -\u003e bool:\n        while any(('()' in s, '[]' in s, '{}' in s)): s = s.replace('()', '').replace('[]', '').replace('{}', '')\n        return not s\n\t\n# 国际站上有一种写法是这样的，相比于上面，下面的写法更加优雅（好理解）一点\nclass Solution:\n    def isValid(self, s: str) -\u003e bool:\n        while s:\n            l = len(s)\n            s = s.replace('()', '').replace('[]', '').replace('{}', '')\n            if l == len(s):  break\n        return not s\t\n```\n- 不断删除有效括号直到不能删除，思路简单效率低。另外，stack的方法也很简单，而且快多了。\n\n\t```python\n\tclass Solution:\n\t    def isValid(self, s: str) -\u003e bool:\n\t        stack, d = [], {'{': '}', '[': ']', '(': ')'}\n\t        for p in s:\n\t            if p in d:\n\t                stack += [p];\n\t            elif not (stack and d[stack.pop()] == p):\n\t                return False\n\t        return not stack\n\t```\n\n## [21. Merge Two Sorted Lists 4行](https://leetcode.com/problems/merge-two-sorted-lists/)\n\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -\u003e ListNode:\n        if l1 and l2:\n            if l1.val \u003e l2.val: l1, l2 = l2, l1\n            l1.next = self.mergeTwoLists(l1.next, l2)\n        return l1 or l2\n```\n- 7 or 9 等于 7\n- None and 7 等于 None\n## [23. Merge k Sorted Lists 4行](https://leetcode.com/problems/merge-k-sorted-lists/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def mergeKLists(self, lists: List[ListNode]) -\u003e ListNode:\n        r, n, p = [], lists and lists.pop(), None\n        while lists or n: r[len(r):], n = ([n], n.next or lists and lists.pop()) if n else ([], lists.pop())\n        for n in sorted(r, key=lambda x: x.val, reverse=True): n.next, p = p, n\n        return n if r else []\n```\n- 本题思路：\n\t1. 把题目给的所有链表中的所有节点放进一个列表 r。\n\t2. 对这个列表 r 中的所有节点进行从大到小的排序。O(NlogN)\n\t3. 把每个节点的指针指向前一个节点。（第一个节点，也就是最大的那个，指向None。）\n\t4. 返回最后一个节点，也就是整个新链表的开头。\n\n- 如何把所有节点放进 r(result link)？\n\n\t我们首先初始化 r 为空列表，初始化 n(node) 为题目所给的第一个链表的开头节点，并删除lists中的这个节点，接着进入while循环，如果 n 不为空，那么 r += [n]，这里使用了切片的技巧（r[len(r):]=[n]相当于r=r+[n]），n=n.next，如果n是第一个链表的最后一个节点的话n.next就是None，下一次while的时候如果lists不为空就说明还有别的链表，此时n为None，我们让 r 不变，n=lists.pop()，也就是从lists中再取下一个节点赋值给n，重复以上步骤直到 lists 为空，我们就把所有节点放进 r 了。\n\t\n- 怎么对 r 排序？\n\n\t用了sorted函数，其中key定义了排序时用来比较的是每个元素的val属性，同时设置reverse为True代表降序排序。\n\t\n- 如何修改每个节点的指针？\n\n\t我们初始化 p(previous node) 为None。遍历降序排好的列表 r，r中的第一个元素就是值最大的元素，也就是我们应该返回的链表的结尾，我们设置它指向None，然后让p=这个节点，继续for循环。之后每经过一个节点 n 就把这个节点的next属性设置为上一个节点 p，遍历完成之后的 n，也就是我们遍历经过的最后一个元素，拥有最小的值，自然就是整个新链表的起始节点，我们将其作为输出值，函数返回。\n## [24. Swap Nodes in Pairs 3行](https://leetcode.com/problems/swap-nodes-in-pairs/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def swapPairs(self, head: ListNode) -\u003e ListNode:\n        if head and head.next:\n            head.next.next, head.next, head = head, self.swapPairs(head.next.next), head.next\n        return head\n```\n- 每次递归交换两个节点，并返回新头参与上次递归\n- 多值交换参考[`这里`](#常用技巧总结)\n## [26. Remove Duplicates from Sorted Array 3行](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)\n\n```python\nclass Solution:\n    def removeDuplicates(self, nums: List[int]) -\u003e int:\n        for i in range(len(nums)-1, 0, -1):\n            if nums[i] == nums[i-1]: nums.pop(i)\n        return len(nums)\n```\n- 时间效率O(N^2), pop操作的平均时间复杂度为O(N), 空间效率O(1)，逆遍历可以防止删除某个元素后影响下一步索引的定位\n- 每次删除数组元素会引发大量的数据迁移操作，使用以下算法解题效率更高\n\t```python\n\tclass Solution:\n\t    def removeDuplicates(self, nums: List[int]) -\u003e int:\n\t\ti = 0\n\t\tfor j in range(1, len(nums)):\n\t\t    if nums[j] != nums[i]:\n\t\t\tnums[i + 1] = nums[j]\n\t\t\ti += 1\n\t\treturn i + 1 if nums else 0\n\t```\n\t- 此解法思路同官方题解\n\t- 数组完成排序后，我们可以放置两个指针 i 和 j，其中 i 是慢指针，而 j 是快指针。只要 nums[i] = nums[j]，我们就增加 j 以跳过重复项。当我们遇到 nums[j] != nums[i]时，跳过重复项的运行已经结束，因此我们必须把它（nums[j]）的值复制到 nums[i + 1]。然后递增 i，接着我们将再次重复相同的过程，直到 j 到达数组的末尾为止\n## [28. Implement strStr() 1行](https://leetcode.com/problems/implement-strstr/)\n\n```python\nclass Solution:\n    def strStr(self, haystack: str, needle: str) -\u003e int:\n\t\treturn haystack.find(needle)\n```\n- 不用内置函数也可以\n\n\t```python\n\tclass Solution:\n\t\tdef strStr(self, haystack: 'str', needle: 'str') -\u003e 'int':\n\t\t    for i in range(0, len(haystack) - len(needle) + 1):\n\t\t        if haystack[i:i+len(needle)] == needle:\n\t\t            return i\n\t    \treturn -1\n\t```\n## [29. Divide Two Integers 5行](https://leetcode.com/problems/divide-two-integers/)\n```python\nclass Solution:\n    def divide(self, dividend: int, divisor: int) -\u003e int:\n        a, b, r, t = abs(dividend), abs(divisor), 0, 1\n        while a \u003e= b or t \u003e 1:\n            if a \u003e= b: r += t; a -= b; t += t; b += b\n            else: t \u003e\u003e= 1; b \u003e\u003e= 1\n        return min((-r, r)[dividend ^ divisor \u003e= 0], (1 \u003c\u003c 31) - 1)\n```\n- 让被除数不断减去除数，直到不够减。每次减完后除数翻倍，并记录当前为初始除数的几倍（用 t 表示倍数 time），若发现不够减且 t 不为 1 则让除数变为原来的一半， t 也减半\n- a 为被除数绝对值，b 为除数绝对值，r 表示 result，t 表示当前除数对于原始除数的倍数\n- a \u003c\u003c b 相当于 `a * 2**b`，a \u003e\u003e b 相当于 `a // 2**b`\n- 异或操作 ^ 可以判断俩数字是否异号\n## [33. Search in Rotated Sorted Array 3行](https://leetcode.com/problems/search-in-rotated-sorted-array/)\n```python\nclass Solution:\n    def search(self, nums, target):\n        self.__class__.__getitem__ = lambda self, m: not(target \u003c nums[0] \u003c= nums[m] or nums[0] \u003c= nums[m] \u003c target or nums[m] \u003c target \u003c= nums[-1])\n        i = bisect.bisect_left(self, True, 0, len(nums))\n        return i if target in nums[i:i+1] else -1\n```\n- 作出数列的函数图像，可以看作是一个含断点的局部递增函数，形如:zap:，前面一段总是比较高\n- python 中 bisect 模块针对的是 list, 如果直接构造 list，相当于遍历所有元素，时间复杂度为 O(N) 而不是 O(logN)，因此我们修改当前类的魔法方法伪造 list，然后用当前类代替list\n- 用二分搜索时，m 代表 middle，low 代表 low，hi 代表 high，当满足任一条件｛① targe \u003c middle 且 middle 在前一段上 且 target \u003c nums[0] ② target \u003e middle 且 middle 在第一段上 ③ target \u003e middle 且 middle 在第二段上 且 target \u003c= nums[-1]｝时，应该向右搜索，因此 getitem 返回 False。\n- 另外还有一种简单的思路：二分法找到断点的位置恢复原始数组，然后正常二分法即可\n\t```python\n\tclass Solution:\n\t    def search(self, nums, target):\n\t\tlo, hi, k = 0, len(nums) - 1, -1\n\t\twhile lo \u003c= hi:\n\t\t    m = (lo + hi) // 2\n\t\t    if m == len(nums) - 1 or nums[m] \u003e nums[m+1]:\n\t\t\tk = m + 1\n\t\t\tbreak\n\t\t    elif m == 0 or nums[m] \u003c nums[m-1]:\n\t\t\tk = m\n\t\t\tbreak\n\t\t    if nums[m] \u003e nums[0]:\n\t\t\tlo = m + 1\n\t\t    else:\n\t\t\thi = m - 1\n\t\ti = (bisect.bisect_left(nums[k:] + nums[:k], target) + k) % max(len(nums), 1)\n\t\treturn i if nums and nums[i] == target else -1\n\t```\n\n## [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/)\n\n- 用自带的bisect函数，一行\n\n```python3\nclass Solution:\n    def searchRange(self, nums: List[int], target: int) -\u003e List[int]:\n        # if not nums or target not in nums:  return [-1, -1]\n        return [bisect.bisect_left(nums, target), bisect.bisect_right(nums, target)-1] \\\n            if nums and target in nums else [-1, -1]\n```\n\n## [35. Search Insert Position 1行](https://leetcode.com/problemset/all/?search=35)\n```python\nclass Solution:\n    def searchInsert(self, nums: List[int], target: int) -\u003e int:\n        return bisect.bisect_left(nums, target, 0, len(nums))\n```\n## [36. Valid Sudoku 4行](https://leetcode.com/problems/valid-sudoku/)\n```python\nclass Solution:\n    def isValidSudoku(self, board: List[List[str]]) -\u003e bool:\n        row = [[x for x in y if x != '.'] for y in board]\n        col = [[x for x in y if x != '.'] for y in zip(*board)]\n        pal = [[board[i+m][j+n] for m in range(3) for n in range(3) if board[i+m][j+n] != '.'] for i in (0, 3, 6) for j in (0, 3, 6)]\n        return all(len(set(x)) == len(x) for x in (*row, *col, *pal))\n```\n- 利用 set 检查每个区块中是否有重复数字\n- pal 取区块的遍历方式是利用 i，j 遍历每个宫格左上角位置，然后取 3*3 区块\n## [38. Count and Say 1行](https://leetcode.com/problems/count-and-say/)\n\n```python\nclass Solution:\n    def countAndSay(self, n: int) -\u003e str:\n        return '1' * (n is 1) or re.sub(r'(.)\\1*', lambda m: str(len(m.group())) + m.group(1), self.countAndSay(n - 1))\n```\n- 正则表达式 re.sub(正则，替换字符串或函数，被替换字符串，是否区分大小写)\n- . 可匹配任意一个除了\\n的字符\n(.) 匹配任意一个除了\\n的字符并把这个匹配结果放进第一组\n(.)\\1 匹配一个任意字符的二次重复并把那个字符放入数组\n(.)\\1* 匹配一个任意字符的多次重复并把那个字符放入数组\n- group(default=0)可以取匹配文本   group(1)取第一个括号内的文本\n## [43. Multiply Strings 5行](https://leetcode.com/problems/multiply-strings/)\n```python\nclass Solution:\n    def multiply(self, num1: str, num2: str) -\u003e str:\n        d = {}\n        for i, n1 in enumerate(num1[::-1]):\n            for j, n2 in enumerate(num2[::-1]): d[i + j] = d.get(i + j, 0) + int(n1) * int(n2)\n        for k in [*d]: d[k + 1], d[k] = d.get(k + 1, 0) + int(d[k] * 0.1), d[k] % 10\n        return re.sub('^0*', '', ''.join(map(str, d.values()))[::-1]) or '0'\n```\n- 本题的难点在于计算整数的时候不能超过32bits，因此使用竖式计算\n- 我们遍历num1中的每个数字n1，然后带着这个数字遍历num2中的每个数字n2做乘法，所得乘积放进 d 中相应的位置然后逐位计算结果\n- i + j 正好对应俩个数字相乘后所在的位置，比如 0 + 0 就应该是个位， 0 + 1 就是十位， 1 + 1 百位。这里所说的位置可以参考[这篇博客中的过程图](https://blog.csdn.net/Give_me_the_who/article/details/80313860)\n- 若完全不想使用int()可以参考：\n\t```python\n\tclass Solution:\n\t    def multiply(self, num1: str, num2: str) -\u003e str:\n\t\td = {}\n\t\tfor i, n1 in enumerate(num1[::-1]):\n\t\t    for j, n2 in enumerate(num2[::-1]):\n\t\t\td[i + j] = d.get(i + j, 0) + (ord(n1) - 48) * (ord(n2) - 48)\n\t\tfor k in [*d]:\n\t\t    d[k + 1], d[k] = d.get(k + 1, 0) + math.floor(d[k] * 0.1), d[k] % 10\n\t\treturn re.sub('^0*', '', ''.join(map(str, d.values()))[::-1]) or '0'\n\t```\n## [46. Permutations 1行](https://leetcode.com/problems/permutations/)\n```python\nclass Solution:\n    def permute(self, nums: List[int]) -\u003e List[List[int]]:\n        return [[n] + sub for i, n in enumerate(nums) for sub in self.permute(nums[:i] + nums[i+1:])] or [nums]\n```\n- 每次固定第一个数字递归地排列数组剩余部分\n- python 有内置函数可以直接实现\n\n\t```python\n\tclass Solution:\n\t    def permute(self, nums: List[int]) -\u003e List[List[int]]:\n\t\tfrom itertools import permutations\n\t\treturn list(permutations(nums))\n\t```\n## [48. rotate-image 1行](https://leetcode.com/problems/rotate-image/)\n先转置后镜像对称\n```python\nclass Solution:\n    def rotate(self, matrix: List[List[int]]) -\u003e None:\n        \"\"\"\n        Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        matrix[:] = [i[::-1] for i in zip(*matrix)]\n```\n加 [:] 才会修改原列表\n## [49. Group Anagrams 1行](https://leetcode.com/problems/group-anagrams/)\n```python\nclass Solution:\n    def groupAnagrams(self, strs):\n        return [[*x] for _, x in itertools.groupby(sorted(strs, key=sorted), sorted)]\n```\n- 使用 groupby 函数依据 sorted 结果分组\n## [50. Pow(x, n) 2行](https://leetcode.com/problems/powx-n/)\n```python\nclass Solution:\n    def myPow(self, x, n, r=1) -\u003e float:\n        x, n = n \u003c 0 and 1 / x or x, abs(n)\n        return self.myPow(x * x, n // 2, r * (not n % 2 or x)) if n else r\n```\n- 尾递归 O(logN) 解法\n- x^4 正常计算过程：x * x * x * x，O(N)\n- 优化后：(x**2)**2，O(logN)\n## [53. Maximum Subarray 2行](https://leetcode.com/problems/maximum-subarray/)\n```python\nclass Solution:\n    def maxSubArray(self, nums):\n        from functools import reduce\n        return reduce(lambda r, x: (max(r[0], r[1]+x), max(r[1]+x,x)), nums, (max(nums), 0))[0]\n```\n- [reduce 函数详解](https://www.cnblogs.com/XXCXY/p/5180245.html)\n- r[0]代表以当前位置为结尾的局部最优解\n- r[1]代表全局最优解\n- 直接DP的解法更好理解一些\n\n\t```python\n\tclass Solution:\n\t    def maxSubArray(self, nums: List[int]) -\u003e int:\n\t        for i in range(1, len(nums)):\n\t            nums[i] = max(nums[i], nums[i] + nums[i-1])\n\t        return max(nums)\n\t```\n## [54. Spiral Matrix 1行](https://leetcode.com/problems/spiral-matrix/)\n```python\nclass Solution:\n    def spiralOrder(self, matrix: List[List[int]]) -\u003e List[int]:\n        return matrix and [*matrix.pop(0)] + self.spiralOrder([*zip(*matrix)][::-1])\n```\n- 为什么是`[*matrix.pop(0)]`而不是`matrix.pop(0)`？因为对于后面的递归，传进来的列表中元素是tuple\n## [58. Length of Last Word 1行](https://leetcode.com/problems/length-of-last-word/)\n```python\nclass Solution:\n    def lengthOfLastWord(self, s: str) -\u003e int:\n        return len(s.strip(' ').split(' ')[-1])\n```\n## [59. Spiral Matrix II 3行](https://leetcode.com/problems/spiral-matrix-ii/)\n```python\nclass Solution:\n    def generateMatrix(self, n: int) -\u003e List[List[int]]:\n        r, n = [[n**2]], n**2\n        while n \u003e 1: n, r = n - len(r), [[*range(n - len(r), n)]] + [*zip(*r[::-1])]\n        return r\n```\n- 流程图\n```\n||  =\u003e  |9|  =\u003e  |8|      |6 7|      |4 5|      |1 2 3|\n\t\t |9|  =\u003e  |9 8|  =\u003e  |9 6|  =\u003e  |8 9 4|\n\t\t\t\t     |8 7|      |7 6 5|\n```\n## [61. Rotate List 4行](https://leetcode.com/problems/rotate-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def rotateRight(self, head: ListNode, k: int) -\u003e ListNode:\n        l = []\n        while head: l[len(l):], head = [head], head.next\n        if l: l[-1].next, l[-1 - k % len(l)].next = l[0], None\n        return l[- k % len(l)] if l else None\n```\n## [62. Unique Paths 1行](https://leetcode.com/problems/unique-paths/)\n\n```python\nclass Solution:\n    def uniquePaths(self, m: int, n: int) -\u003e int:\n        return int(math.factorial(m+n-2)/math.factorial(m-1)/math.factorial(n-1))\n```\n\n- 题目可以转换为排列组合问题，解是C(min(m,n), m+n)，从m+n个中选出m个下移或n个右移。\n- 用DP做也很快，以后自己算 C(a, b) 也可以用算这题的DP法代替\n- math.factorial 的速度不亚于DP，可能内部有优化\n- 0的阶乘为1\n## [66. Plus One 1行](https://leetcode.com/problems/plus-one/)\n\n```python\nclass Solution:\n    def plusOne(self, digits: List[int]) -\u003e List[int]:\n        return list(map(int, str(int(''.join(map(str, digits))) + 1)))\n```\n## [67. Add Binary 1行](https://leetcode.com/problems/add-binary/)\n```python\nclass Solution:\n    def addBinary(self, a: str, b: str) -\u003e str:\n        return bin(int(a, 2) + int(b, 2))[2:]\n```\n- 非内置函数解法：\n```python\nclass Solution:\n    def addBinary(self, a: str, b: str) -\u003e str:\n        r, p = '', 0\n        d = len(b) - len(a)\n        a = '0' * d + a\n        b = '0' * -d + b\n        for i, j in zip(a[::-1], b[::-1]):\n            s = int(i) + int(j) + p\n            r = str(s % 2) + r\n            p = s // 2\n        return '1' + r if p else r\n```\n## [69. Sqrt(x) 1行](https://leetcode.com/problems/sqrtx/)\n```python\nclass Solution:\n    def mySqrt(self, x: int) -\u003e int:\n        return int(x ** 0.5)\n```\n出题者应该是希望看到下面的答案：\n```python\nclass Solution:\n    def mySqrt(self, x: int) -\u003e int:\n        r = x\n        while r*r \u003e x:\n            r = (r + x/r) // 2\n        return int(r)\n```\n- 基本不等式(a+b)/2 \u003e=√ab 推导自 (a-b)^2 \u003e= 0，注意 a\u003e0 且 b\u003e0\n- r 代表 result\n## [70. Climbing Stairs 2行](https://leetcode.com/problems/climbing-stairs/)\n\n```python\nclass Solution:\n    def climbStairs(self, n: int) -\u003e int:\n        from functools import reduce\n        return reduce(lambda r, _: (r[1], sum(r)), range(n), (1, 1))[0]\n```\n- dp递归方程：到达当前楼梯的路径数 = 到达上个楼梯的路径数 + 到达上上个楼梯的路径数\n- 这里用一个元组 r 来储存（当前楼梯路径数，下一层楼梯路径数）\n- 利用 reduce 来代替for循环。[reduce 函数详解](https://www.cnblogs.com/XXCXY/p/5180245.html)\n## [71. Simplify Path 4行](https://leetcode.com/problems/simplify-path/)\n```\nclass Solution:\n    def simplifyPath(self, path: str) -\u003e str:\n        r = []\n        for s in path.split('/'):\n            r = {'':r, '.':r, '..':r[:-1]}.get(s, r + [s])\n        return '/' + '/'.join(r)\n```\n\n## [73. 矩阵置零  5行](https://leetcode-cn.com/problems/set-matrix-zeroes/)\n```python\nclass Solution:\n    def setZeroes(self, matrix: List[List[int]]) -\u003e None:\n        row = [[0] * len(i) if 0 in i else i for i in matrix]\n        col = [[0] * len(j) if 0 in j else list(j) for j in zip(*matrix)]\n        col2row = list(map(list, zip(*col)))\n        # 上面一行效果等同：\n        # col2row = [list(i) for i in zip(*col)]\n        for i in range(len(matrix)):\n            matrix[i] = col2row[i] if row[i] != [0] * len(matrix[0]) else row[i]\n```\n- 获取每一行 / 列的值，假如有0 就整行 / 整列置为0\n- 重新将列排序列表转换为行排序列表，即原来的`matrix`中有0的列全为0，行不变\n- `zip(*col)` 返回的是`zip`类型，需要转换成list，其中元素类型为元组\n- 所以之后做了两步转换，先将zip()返回的各个元组转换为list，在将整个转换为list\n- 替换matrix各行， 如果一整行为0， 则替换为0，否则为`col2row`对应的各行\n\n## [74. 搜索二维矩阵 4行](https://leetcode-cn.com/problems/search-a-2d-matrix/)\n```python\nclass Solution:\n    def searchMatrix(self, matrix: List[List[int]], target: int) -\u003e bool:\n        if not matrix or not matrix[0]:  return False\n        col = list(list(zip(*matrix))[0])  # set() -\u003e list()\n        index = bisect.bisect_left(col, target, 0, len(matrix)-1)  # 二分查找\n        return target in (matrix[index] + matrix[index-1])\n```\n- 先获取首列，然后二分类找到这个数所在的行，然后进行判断\n\n\n## [78. Subsets 2行](https://leetcode.com/problems/subsets/)\n```python\nclass Solution:\n    def subsets(self, nums: List[int]) -\u003e List[List[int]]:\n        from itertools import combinations\n        return sum([list(combinations(nums, i)) for i in range(len(nums) + 1)], [])\n```\n\n## [80. 删除排序数组中的重复项 II 4行](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/)\n```python\ndef removeDuplicates(nums: [int]) -\u003e int:\n    for i in range(len(nums)-3, -1, -1):\n        if nums[i] == nums[i+1] and nums[i] == nums[i+2]:\n            nums.pop(i)\n    return len(nums)\n```\n- 从尾部开始考虑\n\n## [81. 搜索旋转排序数组 II 1行](https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/)\n```python\ndef search(nums: [int], target: int) -\u003e bool:\n    return target in nums\n```\n\n## [83. Remove Duplicates from Sorted List 3行](https://leetcode.com/problems/remove-duplicates-from-sorted-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def deleteDuplicates(self, head: ListNode) -\u003e ListNode:\n        if head:\n            head.next = self.deleteDuplicates(head.next)\n            return head.next if head.next and head.val == head.next.val else head\n```\n- 如果当前节点和下一个节点的值相同，则返回第二个节点\n- 在每个递归中将下一个递归结果连接到当前节点\n\n## [88. Merge Sorted Array 1行](https://leetcode.com/problems/merge-sorted-array/)\n\n```python\nclass Solution:\n    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -\u003e None:\n        \"\"\"\n        Do not return anything, modify nums1 in-place instead.\n        \"\"\"\n        while n \u003e 0: nums1[m+n-1], m, n = (nums1[m-1], m-1, n) if m and nums1[m-1] \u003e nums2[n-1] else (nums2[n-1], m, n-1)\n```\n- 这种题倒着算更容易\n- 上面那行代码其实就相当于：\n\t\n\t```python\n\tclass Solution:\n\t    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -\u003e None:\n\t        \"\"\"\n\t        Do not return anything, modify nums1 in-place instead.\n\t        \"\"\"\n\t        while n \u003e 0:\n\t            if m and nums1[m-1] \u003e nums2[n-1]:\n\t                nums1[m+n-1], m, n = nums1[m-1], m-1, n\n\t            else:\n\t                nums1[m+n-1], m, n = nums2[n - 1], m, n-1\n\t```\n## [89. Gray Code 1行](https://leetcode.com/problems/gray-code/)\n```python\nclass Solution:\n    def grayCode(self, n: int) -\u003e List[int]:\n        return (lambda r: r + [x | 1\u003c\u003cn-1 for x in r[::-1]])(self.grayCode(n-1)) if n else [0]\n```\n- 前4个结果：\n\t```\n\t[0]\n\t[0 1]\n\t[00 01 11 10]\n\t[000 001 011 010 110 111 101 100]\n\t```\n- 递归方程：这一步结果 = 上一步结果 + 上一步结果的镜像并在每个二进制数字前面加一位1\n- \u003c\u003c 左移符号，即在二进制表示后加一位 0 ，例子：3\u003c\u003c1 等于 6`（011 → 110）`，相当于 3 * 2的1次方\n- x | 1\u003c\u003cn-1 就是在十进制数字 x 的二进制前面加一位1之后的十进制结果，比如 x = 1，有 1 | 10 等于 110\n- 循环可以避免一些不必要的操作，会比递归快一些：\n\t```python\n\tclass Solution:\n\t    def grayCode(self, n: int) -\u003e List[int]:\n\t\tr = [0]\n\t\tfor i in range(n):\n\t\t    r.extend([x | 1\u003c\u003ci for x in r[::-1]])\n\t\treturn r\n\t```\n- 或者直接背格雷码的公式🥶吧：\n```python\nclass Solution:\n    def grayCode(self, n: int) -\u003e List[int]:\n        return [i ^ i \u003e\u003e 1  for i in range(1 \u003c\u003c n)]\n```\n## [91. Decode Ways 4行](https://leetcode.com/problems/decode-ways/)\n```python\nclass Solution:\n    def numDecodings(self, s: str) -\u003e int:\n        pp, p = 1, int(s[0] != '0')\n        for i in range(1, len(s)):\n            pp, p = p, pp * (9 \u003c int(s[i-1:i+1]) \u003c= 26) + p * (int(s[i]) \u003e 0)\n        return p\n```\n- 输入 '12' 的结果为 2，如果我们在 '12' 后面增加一个数字 3，输入变成 '123'，结果是 '12'的结果 + '1'的结果 = 3\n- i 从索引 1 开始逐渐遍历 s，当前位置对应结果 = 上上次结果(如果 i 位置字符和 i-1 位置字符的组合满足条件) + 上次结果(如果 s[i] 不为 0)\n## [94. Binary Tree Inorder Traversal 2行](https://leetcode.com/problems/binary-tree-inorder-traversal/)\n```python\n# 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\nclass Solution:\n    def inorderTraversal(self, root: TreeNode) -\u003e List[int]:\n        f = self.inorderTraversal\n        return f(root.left) + [root.val] + f(root.right) if root else []\n```\n- 递归\n```python\nclass Solution:\n    def inorderTraversal(self, root: TreeNode) -\u003e List[int]:\n        r, stack = [], []\n        while True:\n            while root:\n                stack.append(root)\n                root = root.left\n            if not stack:\n                return r\n            node = stack.pop()\n            r.append(node.val)\n            root = node.right\n        return r\n```\n- 迭代\n## [98. Validate Binary Search Tree 3行](https://leetcode.com/problems/validate-binary-search-tree/)\n```python\n# 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\nclass Solution:\n    def isValidBST(self, root: TreeNode, first=True) -\u003e bool:\n        if not root: return first or []\n        l = self.isValidBST(root.left, 0) + [root.val] + self.isValidBST(root.right, 0)\n        return all([a \u003e b for a, b in zip(l[1:], l)]) if first else l\n```\n- 搜索二叉树的中序遍历结果呈升序\n## [101. Symmetric Tree 5行](https://leetcode.com/problems/symmetric-tree/)\n```python\n# 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\nclass Solution:\n    def isSymmetric(self, root: TreeNode) -\u003e bool:\n        if not root or root.left is root.right: return True\n        l, r, i, o = root.left, root.right, TreeNode(0), TreeNode(0)\n        if (l and l.val) != (r and r.val): return False\n        i.left, i.right, o.left, o.right = l.left, r.right, l.right, r.left\n        return self.isSymmetric(i) and self.isSymmetric(o)\n```\n- 一棵树对称意味着：\n\t- 左节点 == 右节点\n\t- 左节点的左子树与右节点右子树对称\n\t- 左节点的右子树与右节点左子树对称\n- 前三行处理特殊情况：root为None或root无子节点直接返回True，root只有一个子节点或root两个子节点不相等直接返回False\n- 第一个条件在前三行处理过了，对于第二和第三个条件，我们分别构造两个假树i(inner)和o(outer)，i代表内假树，对应条件二，o代表外假树，对应条件三。递归内外假树即可\n## [104. Maximum Depth of Binary Tree 1行](https://leetcode.com/problems/maximum-depth-of-binary-tree/)\n```python\n# 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\nclass Solution:\n    def maxDepth(self, root: TreeNode) -\u003e int:\n        return max(map(self.maxDepth,(root.left, root.right))) + 1 if root else 0\n```\n- 利用map函数递归左右节点获取最大值，map函数会将参数一所指向的函数应用于参数二里的所有对象并返回所有结果构成的迭代器\n## [110. 平衡二叉树 3行](https://leetcode-cn.com/problems/balanced-binary-tree/)\n```python\n# 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\nclass Solution:\n    def isBalanced(self, root: TreeNode, first=True) -\u003e bool:\n        if not root: return first or 0\n        l, r = map(lambda x: self.isBalanced(x, False), [root.left, root.right])\n        return max(l,r)+1 if min(l,r)\u003e-1 and abs(l-r)\u003c=1 else (-1, False)[first]\n```\n- DFS递归每个节点\n- 如果这个节点不平衡，那么这棵树肯定不平衡，它和它的所有父节点都返回 -1（根节点返回False）\n- 如果节点平衡，则返回当前树的高度 + 1（根节点返回True）\n## [112. Path Sum 3行](https://leetcode.com/problems/path-sum/)\n```python\n# 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\nclass Solution:\n    def hasPathSum(self, root: TreeNode, sum: int) -\u003e bool:\n        if not root: return False\n        l, r, f = root.left, root.right, lambda x: self.hasPathSum(x, sum - root.val)\n        return l is r and sum == root.val or f(l) or f(r)\n```\n- 考虑初始状态：当树不存在时直接返回 False\n- 考虑支路1：当前节点为叶节点时直接判断总和是否达到要求\n- 考虑支路2：当前节点为非叶节点时将总和缩小并继续递归，判断左右节点是否存在满足条件的\n- 当递归函数到达叶节点时，sum 已经被削减了多次，此时 `sum - node.val` 即为 `原始的sum - 整条路径的总和`\n## [118. Pascal's Triangle 1行](https://leetcode.com/problems/pascals-triangle/)\n```python\nclass Solution:\n    def generate(self, numRows: int) -\u003e List[List[int]]:\n        return [[math.factorial(i)//math.factorial(i-j)//math.factorial(j) for j in range(i+1)] for i in range(numRows)]\n```\n- 参考了杨辉三角的数学性质，[维基百科](https://en.wikipedia.org/wiki/Pascal%27s_triangle)\n- 正常迭代方法：\n\t```python\n\tclass Solution:\n\t    def generate(self, numRows: int) -\u003e List[List[int]]:\n\t\tr = [[1]]\n\t\tfor i in range(1, numRows):\n\t\t    r.append([1] + [sum(r[-1][j:j+2]) for j in range(i)])\n\t\treturn numRows and r or []\n\t```\n## [121. Best Time to Buy and Sell Stock 2行](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)\n```python\nclass Solution:\n    def maxProfit(self, prices: List[int]) -\u003e int:\n        from functools import reduce\n        return reduce(lambda r, p: (max(r[0], p-r[1]), min(r[1], p)), prices, (0, float('inf')))[0]\n```\n- r = (结果，之前遍历过的所有元素中的最小值)\n- [reduce 函数详解](https://www.cnblogs.com/XXCXY/p/5180245.html)\n```python\nclass Solution:\n    def maxProfit(self, prices: List[int]) -\u003e int:\n        r, m = 0, float('inf')\n        for p in prices:\n            r, m = max(r, p - m), min(m, p)\n        return r\n```\n## [122. Best Time to Buy and Sell Stock II 2行](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)\n```python\nclass Solution:\n    def maxProfit(self, prices: List[int]) -\u003e int:\n        return sum(b - a for a, b in zip(prices, prices[1:]) if b \u003e a)\n```\n- 本题可以在同一天买入和卖出，因此只要当天票价比昨天的高就可以卖出\n## [124. Binary Tree Maximum Path Sum 4行](https://leetcode.com/problems/binary-tree-maximum-path-sum/)\n```python\n# 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\nclass Solution:\n    def maxPathSum(self, root: TreeNode, ok=True) -\u003e int:\n        if not root: return 0\n        l, r = self.maxPathSum(root.left, False), self.maxPathSum(root.right, False)\n        self.max = max(getattr(self, 'max', float('-inf')), l + root.val + r)\n        return self.max if ok else max(root.val + max(l, r), 0)\n```\n- 使用 self.max 记录全局最大值，getattr 返回自身 max 属性的值或预定义的负无穷\n- 本题思路是：递归每一个节点，返回`max(以当前节点为结尾的最大路径和,0)`。并更新最大值`全局最大路径和=max(全局最大路径和，当前节点值+左子树返回结果+右子树返回结果)`\n- 用ok判断是不是第一次递归，是就返回全局最大值，否则照常\n## [133. Clone Graph](https://leetcode.com/problems/clone-graph/)\n```python\n\"\"\"\n# Definition for a Node.\nclass Node:\n    def __init__(self, val, neighbors):\n        self.val = val\n        self.neighbors = neighbors\n\"\"\"\nclass Solution:\n    def cloneGraph(self, node: 'Node') -\u003e 'Node':\n        return copy.deepcopy(node)\n```\n- dfs解法请参考 [133克隆图](#133-克隆图)\n## [136. Single Number 2行](https://leetcode.com/problems/single-number/)\n```python\nclass Solution:\n    def singleNumber(self, nums: List[int]) -\u003e int:\n        from functools import reduce\n        return reduce(xor, nums)\n```\n- 这里用到了异或（xor），相同的数字异或后为0，0异或任何数都等于那个数，用reduce在列表所有元素之间使用异或^，那么留下的就是那个单独的数字了\n## [138. Copy List with Random Pointer 1行](https://leetcode.com/problems/copy-list-with-random-pointer/)\n```python\n\"\"\"\n# Definition for a Node.\nclass Node:\n    def __init__(self, val, next, random):\n        self.val = val\n        self.next = next\n        self.random = random\n\"\"\"\nclass Solution:\n    def copyRandomList(self, head: 'Node') -\u003e 'Node':\n        return copy.deepcopy(head)\n```\n- 内置函数\n## [139. Word Break 8行](https://leetcode.com/problems/word-break/)\n```python\nclass Solution:\n    def wordBreak(self, s, wordDict):\n        \n        def f(s, d={}):\n            if not s in d:\n                for i in range(1, 1 + len(s)):\n                    d[s[:i]] = s[:i] in wordDict and (i == len(s) or f(s[i:]))\n                    if d[s[:i]]: return True\n                return False\n            return d[s]\n        \n        return f(s)\n```\n- brute force + memory\n## [141. Linked List Cycle 2行](https://leetcode.com/problems/linked-list-cycle/)\n```python\n# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution(object):\n    def hasCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        while head and head.val != None: head.val, head = None, head.next\n        return head != None\n```\n- 这题不支持python3，所以用pyhton2解法代替，下题记得调回来 :baby_chick:\n- 破坏走过的所有节点，下次再遇到就知道了\n- 不过以上方法会丢失原有信息，一般解法为快慢指针\n```python\n# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution(object):\n    def hasCycle(self, head):\n        slow = fast = head\n        while fast and fast.next:\n            fast = fast.next.next\n            slow = slow.next\n            if slow == fast:\n                return True\n        return False\n```\n## [142. Linked List Cycle II 5行](https://leetcode.com/problems/linked-list-cycle-ii/)\n```python\n# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution(object):\n    def detectCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        s = {None}\n        while head not in s:\n            s.add(head)\n            head = head.next\n        return head\n```\n- 把见过的节点丢集合里，下次再遇见就是环的开始\n- 还有一个纯数学的快慢指针解法，设环的起始节点为 E，快慢指针从 head 出发，快指针速度为 2，设相交节点为 X，head 到 E 的距离为 H，E 到 X 的距离为 D，环的长度为 L，那么有：快指针走过的距离等于慢指针走过的距离加快指针多走的距离（多走了 n 圈的 L） `2(H + D) = H + D + nL`，因此可以推出 `H = nL - D`，这意味着如果我们让俩个慢指针一个从 head 出发，一个从 X 出发的话，他们一定会在节点 E 相遇\n\t```\n\t\t\t\t  _____\n\t\t\t\t /     \\\n\t\t head___________E       \\\n\t\t\t\t\\       /\n\t\t\t\t X_____/ \n\t```\n\t```python\n\tclass Solution(object):\n\t    def detectCycle(self, head):\n\t\tslow = fast = head\n\t\twhile fast and fast.next:\n\t\t    fast = fast.next.next\n\t\t    slow = slow.next\n\t\t    if slow == fast:\n\t\t\tbreak\n\t\telse:\n\t\t    return None\n\t\twhile head is not slow:\n\t\t    head = head.next\n\t\t    slow = slow.next\n\t\treturn head\n\t```\n## [146. LRU Cache 7行](https://leetcode.com/problems/lru-cache/)\n```python\nclass LRUCache(object):\n\n    def __init__(self, capacity):\n        self.od, self.cap = collections.OrderedDict(), capacity\n\n    def get(self, key):\n        if key not in self.od: return -1\n        self.od.move_to_end(key)\n        return self.od[key]\n\n    def put(self, key, value):\n        if key in self.od: del self.od[key]\n        elif len(self.od) == self.cap: self.od.popitem(False)\n        self.od[key] = value\n\n\n# Your LRUCache object will be instantiated and called as such:\n# obj = LRUCache(capacity)\n# param_1 = obj.get(key)\n# obj.put(key,value)\n```\n## [148. Sort List 10行](https://leetcode.com/problems/sort-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def sortList(self, head: ListNode) -\u003e ListNode:\n        if not (head and head.next): return head\n        pre, slow, fast = None, head, head\n        while fast and fast.next: pre, slow, fast = slow, slow.next, fast.next.next\n        pre.next = None\n        return self.mergeTwoLists(*map(self.sortList, (head, slow)))\n    \n    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -\u003e ListNode:\n        if l1 and l2:\n            if l1.val \u003e l2.val: l1, l2 = l2, l1\n            l1.next = self.mergeTwoLists(l1.next, l2)\n        return l1 or l2\n```\n- 使用快慢指针寻找链表中点，并分解链表\n- 递归融合俩个有序链表，详解见 21 题\n- 此处忽略了递归开栈导致的非 常数级空间复杂度（想太多了吧:laughing:），如果一定要抬杠，推荐使用quicksort\n\t```python\n\tclass Solution(object):\n\t    def sortList(self, head):\n\t\t\"\"\"\n\t\t:type head: ListNode\n\t\t:rtype: ListNode\n\t\t\"\"\"\n\t\tdef partition(start, end):\n\t\t    node = start.next.next\n\t\t    pivotPrev = start.next\n\t\t    pivotPrev.next = end\n\t\t    pivotPost = pivotPrev\n\t\t    while node != end:\n\t\t\ttemp = node.next\n\t\t\tif node.val \u003e pivotPrev.val:\n\t\t\t    node.next = pivotPost.next\n\t\t\t    pivotPost.next = node\n\t\t\telif node.val \u003c pivotPrev.val:\n\t\t\t    node.next = start.next\n\t\t\t    start.next = node\n\t\t\telse:\n\t\t\t    node.next = pivotPost.next\n\t\t\t    pivotPost.next = node\n\t\t\t    pivotPost = pivotPost.next\n\t\t\tnode = temp\n\t\t    return [pivotPrev, pivotPost]\n\n\t\tdef quicksort(start, end):\n\t\t    if start.next != end:\n\t\t\tprev, post = partition(start, end)\n\t\t\tquicksort(start, prev)\n\t\t\tquicksort(post, end)\n\n\t\tnewHead = ListNode(0)\n\t\tnewHead.next = head\n\t\tquicksort(newHead, None)\n\t\treturn newHead.next\n\t```\n## [150. Evaluate Reverse Polish Notation 5行](https://leetcode.com/problems/evaluate-reverse-polish-notation/)\n```python\nclass Solution:\n    def evalRPN(self, tokens: List[str]) -\u003e int:\n        t, f = tokens.pop(), self.evalRPN\n        if t in '+-*/':\n            b, a = f(tokens), f(tokens)\n            t = eval('a' + t + 'b')\n        return int(t)\n```\n- 递归地返回左右表达式操作后结果\n- eval 函数将字符串看作代码得到输出值\n## [155. Min Stack 每个1行](https://leetcode.com/problems/min-stack/)\n```python\nclass MinStack:\n    \n    def __init__(self):\n        self.data = [(None, float('inf'))]\n\n    def push(self, x: 'int') -\u003e 'None':\n        self.data.append((x, min(x, self.data[-1][1])))\n\n    def pop(self) -\u003e 'None':\n        if len(self.data) \u003e 1: self.data.pop()\n\n    def top(self) -\u003e 'int':\n        return self.data[-1][0]\n\n    def getMin(self) -\u003e 'int':\n        return self.data[-1][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.getMin()\n```\n## [160. Intersection of Two Linked Lists 3行](https://leetcode.com/problems/intersection-of-two-linked-lists/)\n```python\n# Definition for singly-linked list.\n# class ListNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution(object):\n    def getIntersectionNode(self, headA, headB):\n        \"\"\"\n        :type head1, head1: ListNode\n        :rtype: ListNode\n        \"\"\"\n        a, b = (headA, headB) if headA and headB else (None, None)\n        while a != b: a, b = not a and headB or a.next, not b and headA or b.next\n        return a\n```\n- 这题不支持 Python3 所以只能用 Python2 做了\n- 把第一条链表的尾部接到第二条链表的开头，第二条接到第一条的开头，就能消除俩条链表的长度差，并在某一时刻在第一个交叉点相遇，或在走完俩条链表长度的时候同时为 None\n\t```python\n\t# 假设有两条链表1→2→3→4和①→②→③，模拟一下算法流程 ↓\n\n\t1 → 2 ↘  ↗ → 4                               1 → 2 ↘  ↗ → 4 → ① → → → 3(②) ❤ 相遇了\n\t① → → → 3(②) → ③   把4接到①前面，把③接到1前面   ① → → → 3(②) → ③ → 1 → 2 ↗     若非相交链表则同时走到None\n\t```\n## [162. Find Peak Element 2行](https://leetcode.com/problems/find-peak-element/)\n```python\nclass Solution:\n    def findPeakElement(self, nums: List[int]) -\u003e int:\n        self.__class__.__getitem__ = lambda self, i: i and nums[i - 1] \u003e nums[i]\n        return bisect.bisect_left(self, True, 0, len(nums)) - 1\n```\n- [二分查找套路](#-%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE)\n- 如果当前位置的左边是更大的数字，则当前位置置为True，继续向左搜索，最后应该插入的位置 = 我们寻找的位置 + 1，因此最后 - 1\n## [165. Compare Version Numbers 4行](https://leetcode.com/problems/compare-version-numbers/)\n```python\nclass Solution:\n    def compareVersion(self, version1: str, version2: str) -\u003e int:\n        v1, v2 = [*map(int, version1.split('.'))], [*map(int, version2.split('.'))]\n        d = len(v2) - len(v1)\n        v1, v2 = v1 + [0] * d, v2 + [0] * -d\n        return (v1 \u003e v2) - (v1 \u003c v2)\n```\n- 利用 python 序列比较的性质\n## [169. Majority Element 1行](https://leetcode.com/problems/majority-element/)\n```python\nclass Solution:\n    def majorityElement(self, nums: List[int]) -\u003e int:\n        return sorted(nums)[len(nums) // 2]\n```\n## [171. Excel Sheet Column Number 1行](https://leetcode.com/problems/excel-sheet-column-number/)\n```python\nclass Solution:\n    def titleToNumber(self, s: str) -\u003e int:\n        return sum((ord(c) - 64) * 26**i for i, c in enumerate(s[::-1]))\n```\n## [173. Binary Search Tree Iterator 6行](https://leetcode.com/problems/binary-search-tree-iterator/)\n```python\n# 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\nclass BSTIterator:\n\n    def __init__(self, root: TreeNode):\n        self.s = []\n        while root: self.s[len(self.s):], root = [root], root.left\n\n    def next(self) -\u003e int:\n        \"\"\"\n        @return the next smallest number\n        \"\"\"\n        r, root = self.s[-1], self.s.pop().right\n        while root: self.s[len(self.s):], root = [root], root.left\n        return r.val\n\n    def hasNext(self) -\u003e bool:\n        \"\"\"\n        @return whether we have a next smallest number\n        \"\"\"\n        return bool(self.s)\n\n\n# Your BSTIterator object will be instantiated and called as such:\n# obj = BSTIterator(root)\n# param_1 = obj.next()\n# param_2 = obj.hasNext()\n```\n- 模拟中序遍历的迭代过程，使用堆栈 `self.s` 进行深度优先搜索\n- 空间复杂度为 O(树的高度)\n- 平均时间复杂度 = 循环总次数（N） / 迭代器长度（N） = O(1)\n- 迭代器解法：\n```python\nfrom itertools import chain\n\nclass BSTIterator:\n\n    def __init__(self, root: TreeNode):\n        def gen(root): yield from chain(gen(root.left), [root.val], gen(root.right)) if root else ()\n        self.iter, self.len = gen(root), 0\n        for _ in gen(root): self.len += 1\n\n    def next(self) -\u003e int:\n        \"\"\"\n        @return the next smallest number\n        \"\"\"\n        self.len -= 1\n        return next(self.iter)\n\n    def hasNext(self) -\u003e bool:\n        \"\"\"\n        @return whether we have a next smallest number\n        \"\"\"\n        return bool(self.len)\n```\n- 平均时空复杂度： O(1)，O(1)\n## [189. Rotate Array 1行](https://leetcode.com/problems/rotate-array/)\n```python\nclass Solution:\n    def rotate(self, nums: List[int], k: int) -\u003e None:\n        \"\"\"\n        Do not return anything, modify nums in-place instead.\n        \"\"\"\n        nums[:] = nums[len(nums) - k:] + nums[:len(nums) - k]\n```\n- 空间复杂度 = O(N)\n- 进阶：\n\t```python\n\tclass Solution:\n\t    def rotate(self, nums: List[int], k: int) -\u003e None:\n\t\t\"\"\"\n\t\tDo not return anything, modify nums in-place instead.\n\t\t\"\"\"\n\t\tfor _ in range(k % len(nums)): nums[-1:], nums[:0] = [], nums[-1:]\n\t```\n\t- 时间复杂度 = O(k % len(nums))，空间复杂度 = O(1)\n## [190. Reverse Bits 1行](https://leetcode.com/problems/reverse-bits/)\n```python\nclass Solution:\n    # @param n, an integer\n    # @return an integer\n    def reverseBits(self, n):\n        return int(bin(n)[2:].zfill(32)[::-1], 2)\n```\n- 字符串操作\n- [zfill用法](https://www.runoob.com/python/att-string-zfill.html)\n## [191. Number of 1 Bits 1行](https://leetcode.com/problems/number-of-1-bits/)\n```python\nclass Solution(object):\n    def hammingWeight(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        return bin(n).count('1')\n```\n## [198. House Robber 2行](https://leetcode.com/problems/house-robber/)\n```python\nclass Solution:\n    def rob(self, nums: List[int]) -\u003e int:\n        from functools import reduce\n        return reduce(lambda r, n: (max(r[0], n + r[1]), r[0]), nums, (0, 0))[0]\n```\n- DP递归方程：一直偷到这家的钱 = max（一直偷到上一家的钱，一直偷到上上家的钱 + 这家的钱）😃有点小绕\n- 以上为下面代码的化简版，[reduce 函数详解](https://www.cnblogs.com/XXCXY/p/5180245.html)\n```python\nclass Solution:\n    def rob(self, nums: List[int]) -\u003e int:\n        last, now = 0, 0\n        for i in nums:\n            last, now = now, max(last + i, now)\n        return now\n```\n- DP不一定要数组，这里两个变量就够了，空间复杂度为O(1)\n## [200. Number of Islands 7行](https://leetcode.com/problems/number-of-islands/)\n```python\nclass Solution(object):\n    def numIslands(self, grid):\n        def sink(i, j):\n            if 0 \u003c= i \u003c len(grid) and 0 \u003c= j \u003c len(grid[i]) and int(grid[i][j]):\n                grid[i][j] = '0'\n                for i, j in zip((i, i+1, i, i-1), (j+1, j, j-1, j)): sink(i, j)\n                return 1\n            return 0\n        return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i])))\n```\n- 根据题意，我们可以把每一个陆地点当作树根，用 DFS 搜索四周的陆地并沉没它，那么这一整块的陆地都被沉没了，下次我们再遇到陆地点的时候就说明发现新大陆了\n## [202. Happy Number 1行](https://leetcode.com/problems/happy-number/)\n```python\nclass Solution:\n    def isHappy(self, n: int) -\u003e bool:\n        return self.isHappy(sum(int(i) ** 2 for i in str(n))) if n \u003e 4 else n == 1\n```\n- 不是快乐数的数称为不快乐数(unhappy number)，所有不快乐数的数位平方和计算，最后都会进入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的循环中\n- 这个规律比较难想到的，正常解法是判断n是否会进入循环：\n```python\nclass Solution:\n    def isHappy(self, n: int) -\u003e bool:\n        seen = {1}\n        while n not in seen:\n            seen.add(n)\n            n = sum(int(i) ** 2 for i in str(n))\n        return n == 1\n```\n## [203. Remove Linked List Elements 2行]()\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def removeElements(self, head: ListNode, val: int) -\u003e ListNode:\n        if head: head.next = self.removeElements(head.next, val)\n        return head.next if head and head.val == val else head\n```\n- 递归：每次都返回从当前位置算起第一个有效的节点或None\n## [205. Isomorphic Strings 1行](https://leetcode.com/problems/isomorphic-strings/)\n```python\nclass Solution:\n    def isIsomorphic(self, s: str, t: str) -\u003e bool:\n        return [*map(s.index, s)] == [*map(t.index, t)]\n```\n\n```python\nclass Solution:\n    def isIsomorphic(self, s: str, t: str) -\u003e bool:\n        return all(s.index(i) == t.index(j) for i,j in zip(s,t))\n```\n\n- 同构代表两个字符串中每个位置上字符在自身第一次出现的索引相同\n## [206. Reverse Linked List 2行](https://leetcode.com/problems/reverse-linked-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def reverseList(self, head: ListNode, tail=None) -\u003e ListNode:\n        if head: head.next, tail, head = tail, head, head.next\n        return self.reverseList(head, tail) if head else tail\n```\n- 递归解法\n- 此解法为尾递归，即直接以递归返回值作为结果，一般编译器会做优化，避免多余的函数开栈操作，实现效果相当于迭代\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def reverseList(self, head: ListNode) -\u003e ListNode:\n        p = None\n        while head: head.next, p, head = p, head, head.next\n        return p\n```\n- 迭代解法\n## [215. Kth Largest Element in an Array 1行](https://leetcode.com/problems/kth-largest-element-in-an-array/)\n```python\nclass Solution:\n    def findKthLargest(self, nums: List[int], k: int) -\u003e int:\n        return sorted(nums)[-k]\n```\n- O(NlogN)调库\n- 面试官一般不会接受以上答案的，可以参考下面这个O(N)的quick-selection，思路借鉴的quick-sort\n\t```python\n\tclass Solution:\n\t    def findKthLargest(self, nums: List[int], k: int) -\u003e int:\n\t\tl = [x for x in nums if x \u003e nums[0]]\n\t\tm = [x for x in nums if x == nums[0]]\n\t\tr = [x for x in nums if x \u003c nums[0]]\n\t\tf = self.findKthLargest\n\n\t\tif k \u003c= len(l):\n\t\t    return f(l, k)\n\t\telif k \u003c= len(l) + len(m):\n\t\t    return nums[0]\n\t\treturn f(r, k - len(l) - len(m))\n\t```\n```python\nclass Solution:\n    def findKthLargest(self, nums: List[int], k: int) -\u003e int:\n        return nlargest(k,nums)[-1]\n```\n\n- 用了 heapq 的 nlargest 函数，返回一个 list , 然后取最后一个\n## [217. Contains Duplicate 1行](https://leetcode.com/problems/contains-duplicate/)\n```python\nclass Solution:\n    def containsDuplicate(self, nums: List[int]) -\u003e bool:\n        return len(nums) != len(set(nums))\n```\n## [219. Contains Duplicate II 4行](https://leetcode.com/problems/contains-duplicate-ii/)\n```python\nclass Solution:\n    def containsNearbyDuplicate(self, nums: List[int], k: int) -\u003e bool:\n        r, d = k + 1, {}\n        for i, n in enumerate(nums):\n            r, d[n] = min(r, i - d.get(n, -k - 1)), i\n        return r \u003c= k\n```\n- 本题题目有误，实际意思是找同数字最小间隔，若不超过 k 则满足条件\n- 遍历列表，每次都比对最小间隔，并更新哈希表索引，当前位置往左的最小间隔一定是与上一次同数字出现的索引的距离\n## [225. Implement Stack using Queues 6行](https://leetcode-cn.com/problems/implement-stack-using-queues/submissions/)\n```python\nclass MyStack:\n\n    def __init__(self):\n        self.q = collections.deque()\n\n    def push(self, x):\n        self.q.append(x)\n        for _ in range(len(self.q) - 1): self.q.append(self.q.popleft())\n        \n    def pop(self):\n        return self.q.popleft()\n\n    def top(self):\n        return self.q[0]\n    \n    def empty(self):\n        return not len(self.q)\n```\n- push 的时候把 x 放入队尾，然后遍历一遍原始队列元素，每次弹出之后加入队尾\n## [230. Kth Smallest Element in a BST 3行](https://leetcode.com/problems/kth-smallest-element-in-a-bst/)\n```python\n# 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\nclass Solution:\n    def kthSmallest(self, root, k):\n        from itertools import chain, islice\n        def gen(x): yield from chain(gen(x.left), [x.val], gen(x.right)) if x else ()\n        return next(islice(gen(root), k - 1, k))\n```\n- 本题利用迭代器骚了一波:grinning:，不太了解的话看这里 [yield 推荐阅读博客](https://blog.csdn.net/mieleizhi0522/article/details/82142856)\n- chain 函数可以组合多个迭代器，islice 函数对迭代器做切片操作\n- 此题常规解法 中序遍历 还是需要了解下的\n\t```python\n\t# Definition for a binary tree node.\n\t# class TreeNode(object):\n\t#     def __init__(self, x):\n\t#         self.val = x\n\t#         self.left = None\n\t#         self.right = None\n\n\tclass Solution(object):\n\t    def kthSmallest(self, root, k):\n\t\t\"\"\"\n\t\t:type root: TreeNode\n\t\t:type k: int\n\t\t:rtype: int\n\t\t\"\"\"\n\t\tres = []\n\t\tself.visitNode(root, res)\n\t\treturn res[k - 1]\n\n\t    # 中序遍历\n\t    def visitNode(self, root, res):\n\t\tif root is None:\n\t\t    return\n\t\tself.visitNode(root.left, res)\n\t\tres.append(root.val)\n\t\tself.visitNode(root.right, res)\n\t```\n## [231. 2的幂 1行](https://leetcode.com/problems/power-of-two/)\n```python\nclass Solution:\n    def isPowerOfTwo(self, n: int) -\u003e bool:\n\t\"\"\"\n\t:type n: int\n\t:rtype: bool\n\t\"\"\"\n        return n \u003e 0 and n \u0026 n - 1 == 0\n```\n- 2 的幂的二进制形式最高位一定是1，其余为0\n- 用常规思路也行\n\t```python\n\tclass Solution(object):\n\t    def isPowerOfTwo(self, n):\n\t\treturn n \u003e 0 and 2**int(math.log2(n)) == n\n\t```\n## [232. Implement Queue using Stacks 13行](https://leetcode.com/problems/implement-queue-using-stacks/)\n```python\nclass MyQueue:\n\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.stack = []\n\n    def push(self, x: int) -\u003e None:\n        \"\"\"\n        Push element x to the back of queue.\n        \"\"\"\n        self.stack.append(x)\n\n    def pop(self) -\u003e int:\n        \"\"\"\n        Removes the element from in front of queue and returns that element.\n        \"\"\"\n        temp = []\n        while self.stack: temp.append(self.stack.pop())\n        r = temp.pop()\n        while temp: self.stack.append(temp.pop())\n        return r\n\n    def peek(self) -\u003e int:\n        \"\"\"\n        Get the front element.\n        \"\"\"\n        temp = []\n        while self.stack: temp.append(self.stack.pop())\n        r = temp[-1]\n        while temp: self.stack.append(temp.pop())\n        return r\n\n    def empty(self) -\u003e bool:\n        \"\"\"\n        Returns whether the queue is empty.\n        \"\"\"\n        return not self.stack\n\n\n# Your MyQueue object will be instantiated and called as such:\n# obj = MyQueue()\n# obj.push(x)\n# param_2 = obj.pop()\n# param_3 = obj.peek()\n# param_4 = obj.empty()\n```\n- 使用俩个栈来模拟队列，当需要取第一个元素的时候创建一个临时的栈temp，把栈里面的东西全部抽出来放进temp，完成操作后放回去\n## [234. Palindrome Linked List 3行](https://leetcode.com/problems/palindrome-linked-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def isPalindrome(self, head: ListNode) -\u003e bool:\n        def gen(n):\n            while n: yield n.val; n = n.next\n        return [*gen(head)] == [*gen(head)][::-1]\n```\n## [235. Lowest Common Ancestor of a Binary Search Tree 2行](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/)\n```python\n# 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\nclass Solution:\n    def lowestCommonAncestor(self, root, p, q):\n        while (root.val - p.val) * (root.val - q.val) \u003e 0: root = (root.left, root.right)[p.val \u003e root.val]\n        return root\n```\n- 最近公共祖先的值一定介于p、q值之间(闭区间)\n## [236. Lowest Common Ancestor of a Binary Tree 2行](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/)\n```python\n# 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\nclass Solution:\n    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -\u003e 'TreeNode':\n        l, r = map(lambda x: x and self.lowestCommonAncestor(x, p, q), (root.left, root.right))\n        return (root in (p, q) or l and r) and root or l or r\n```\n- 递归全部节点，p 的祖先节点全部返回 p，q 的祖先节点全部返回 q，除非它同时是俩个节点的最近祖先，也就是 p，q 分别位于左右子树，那么返回自身\n- 这思路用在[235](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/)也行\n## [237. Delete Node in a Linked List 1行](https://leetcode.com/problems/delete-node-in-a-linked-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def deleteNode(self, node):\n        \"\"\"\n        :type node: ListNode\n        :rtype: void Do not return anything, modify node in-place instead.\n        \"\"\"\n        node.val, node.next = node.next.val, node.next.next\n```\n- `node = node.next`是不行的，因为这里只是改了函数参数引用的对象，而原来传进来的 node 没有任何改变\n- 详细说明下：如果Python的函数得到的参数是可变对象（比如list，set，这样的，内部属性可以改变的），那么我们实际得到的是这个对象的浅拷贝。比如这个函数刚刚开始的时候题目传进来一个参数node，我们设这个节点为A，那么实际上得到的参数node是一个对于A的一个浅拷贝，你可以想象node是一把钥匙，它可以打开真正的节点A的门，如果我们现在让`node = node.next`，那么我们只是换了钥匙，变成了打开 A.next 的门的对应的钥匙，因此链表没有被修改， A没有被修改，只是我们手里的钥匙变了。而如果我们直接写`node.val, node.next = node.next.val, node.next.next`，就相当于我们先用钥匙找到 A 的门，然后修改了 A 的属性，链表发生变化\n- 此题考查python函数的传参形式为“传对象引用”，相当于浅拷贝（对于可变对象来说）\n## [238. Product of Array Except Self 5行](https://leetcode.com/problems/product-of-array-except-self/)\n```python\nclass Solution:\n    def productExceptSelf(self, nums: List[int]) -\u003e List[int]:\n        res, l, r = [1] * len(nums), 1, 1\n        for i, j in zip(range(len(nums)), reversed(range(len(nums)))):\n            res[i], l = res[i] * l, l * nums[i]\n            res[j], r = res[j] * r, r * nums[j]\n        return res\n```\n- O(N)双指针双向遍历\n## [240. Search a 2D Matrix II 1行](https://leetcode.com/problems/search-a-2d-matrix-ii/)\n```python\nclass Solution:\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        return any(target in row for row in matrix)\n```\n- 以下为 O(m+n) 解法：\n\t```python\n\tclass Solution:\n\t    def searchMatrix(self, matrix, target):\n\t\t\"\"\"\n\t\t:type matrix: List[List[int]]\n\t\t:type target: int\n\t\t:rtype: bool\n\t\t\"\"\"\n\t\tj = -1\n\t\tfor row in matrix:\n\t\t    while j \u003e -len(row) and row[j] \u003e target:\n\t\t\tj -= 1\n\t\t    if row and row[j] == target:\n\t\t\treturn True\n\t\treturn False\n\t```\n\t- 从矩阵右上角开始，若值比 target 大则证明这一列的值都比 target 大，继续搜索前面的列；若比 target 小说明 target 可能在后面的行中，进入下一行\n## [242. 有效的字母异位词 1行](https://leetcode.com/problems/valid-anagram/)\n```python\nclass Solution:\n    def isAnagram(self, s: str, t: str) -\u003e bool:\n        return Counter(s) == Counter(t)\n```\n- O(n) 思路等于建哈希表\n```python\nclass Solution:\n    def isAnagram(self, s: str, t: str) -\u003e bool:\n        return sorted(s) == sorted(t)\n```\n- O(n log(n)) 排序后相等，原来就相等，利用 python 的 str 可以直接排序的特点\n## [258. Add Digits 1行](https://leetcode.com/problems/add-digits/)\n```python\nclass Solution:\n    def addDigits(self, num: int) -\u003e int:\n        return num % 9 or 9 * bool(num)\n```\n- O(1) 数学推理：设某个数字的字符串表示为`'abc'`，则这个数字代表`a*100 + b*10 + c`，转换后成为`a + b + c`，可见每次转换相当于把原数字减去`a*99 + b*9 = 9 * (a*11 + b)`，可以推出只要高于个位的位置上有数字，算法就会减去一个小于原数字的9的倍数，这就相当于`数字 % 9`。但`9 % 9 = 0`，而 9 本身就没有十位，因此需要考虑原数字是 0 或 9 的倍数的特殊情况\n- 首先计算`num % 9`，若结果为 0 则考虑`num`本身是否为 0，若不为 0 返回 9\n```python\nclass Solution:\n    def addDigits(self, num: int) -\u003e int:\n        while num \u003e 9:\n            num = eval('+'.join(n for n in str(num)))\n        return num\n```\n- 循环判断\n## [268. Missing Number 1行](https://leetcode.com/problems/missing-number/)\n```python\nclass Solution:\n    def missingNumber(self, nums: List[int]) -\u003e int:\n        return sum(range(len(nums) + 1)) - sum(nums)\n```\n- O(N)时间，O(1)空间（迭代器）\n```python\nclass Solution:\n    def missingNumber(self, nums: List[int]) -\u003e int:\n        return int(len(nums) * (len(nums) + 1) / 2 - sum(nums))\n```\n- 等差数列求和公式，O(1)空间\n## [278. First Bad Version 2行](https://leetcode.com/problems/first-bad-version/)\n```python\n# The isBadVersion API is already defined for you.\n# @param version, an integer\n# @return a bool\n# def isBadVersion(version):\n\nclass Solution:\n    def firstBadVersion(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        self.__class__.__getitem__ = lambda self, x: isBadVersion(x)\n        return bisect.bisect_left(self, True, 1, n)\n```\n- 改造当前类的魔法方法getitem以使用内置函数\n- 复现二分搜索解法如下：\n```python\n# The isBadVersion API is already defined for you.\n# @param version, an integer\n# @return a bool\n# def isBadVersion(version):\n\nclass Solution:\n    def firstBadVersion(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        l, h = 1, n\n        while l \u003c= h:\n            m = (l + h) // 2\n            if isBadVersion(m) \u003e m * isBadVersion(m - 1):\n                return m\n            elif isBadVersion(m):\n                h = m - 1\n            else:\n                l = m + 1\n```\n- 本题二分搜索中判断返回的条件为 当前版本为True且（当前索引为0 或 左边的版本为False）\n- `m *` 的作用是避免 `m - 1` 为负数，如果 m 为 0，则代表左边没有版本，只需判断当前版本是否为 True\n- True \u003e False 或 0\n## [279. Perfect Squares 4行](https://leetcode.com/problems/perfect-squares/)\n```python\nclass Solution:\n    def numSquares(self, n: int) -\u003e int:\n        dp = [0]\n        for i in range(1, n+1):\n            dp.append(min(dp[-j*j] for j in range(1, 1 + int(i**0.5))) + 1)\n        return dp[-1]\n```\n- dp方程：总和为 n 的最小完全平方数个数 = min(总和为 (n - 某个完全平方数) 的最小完全平方数个数) + 1\n- 中文版力扣这题用dp会超时，可以[使用bfs](#279-完全平方数)，或者**拉格朗日四平方数和定理** 😎：任何一个正整数都可以表示成不超过四个整数的平方之和。 推论：满足四数平方和定理的数n（四个整数的情况），必定满足 n=4^a(8b+7)\n```python\nclass Solution:\n    def numSquares(self, n: int) -\u003e int:\n        while n % 4 == 0:\n            n /= 4\n        if n % 8 == 7:\n            return 4\n        \n        a = 0\n        while a**2 \u003c= n:\n            b = int((n - a**2)**0.5) \n            if a**2 + b**2 == n:\n                return bool(a) + bool(b) \n            a += 1\n        \n        return 3\n```\n## [283. Move Zeroes 1行](https://leetcode.com/problems/move-zeroes/)\n```python\nclass Solution:\n    def moveZeroes(self, nums: List[int]) -\u003e None:\n        \"\"\"\n        Do not return anything, modify nums in-place instead.\n        \"\"\"\n        nums.sort(key=bool, reverse=True)\n```\n- sort 时间复杂度为O(NlogN), 直接遍历可以达到 O(N)\n```python\nclass Solution:\n    def moveZeroes(self, nums: List[int]) -\u003e None:\n        \"\"\"\n        Do not return anything, modify nums in-place instead.\n        \"\"\"\n        i = 0\n        for i, n in enumerate(filter(lambda x: x, nums)):\n            nums[i] = n\n        for i in range(i + 1, len(nums)):\n            nums[i] = 0\n```\n- 直接使用 filter 迭代器可以避免交换操作，思路更简单\n## [287. Find the Duplicate Number 2行](https://leetcode.com/problems/find-the-duplicate-number/)\n```python\nclass Solution:\n    def findDuplicate(self, nums: List[int]) -\u003e int:\n        self.__class__.__getitem__ = lambda sef, m: sum(n \u003c= m for n in nums) \u003e m\n        return bisect.bisect_left(self, True, 1, len(nums) - 1)\n```\n- 本题可用二分查找，整个算法时间复杂度为 O(NlogN)，由题意可知搜索范围在 1 到 n 之间，那么如何缩小范围？只需判断数组中不超过中间数 m 的元素数量是否大于 m 即可，若大于，则表示范围 1 到 m 内肯定包含重复的数字\n- 搜索范围为 [1, n]，向左（包括target）搜索的条件为：不大于 n 的数字在 nums 存在超过 m 个，即搜索范围可以被缩小为 [1, m]\n## [292. Nim Game 1行](https://leetcode.com/problems/nim-game/)\n```python\nclass Solution:\n    def canWinNim(self, n: int) -\u003e bool:\n        return bool(n % 4)\n```\n- 只要轮到你的时候剩余石头数量不是 4 的倍数都是完胜，因为你有办法使得每次轮到对方的时候剩余石头数量都为 4 的倍数\n## [326. Power of Three 1行](https://leetcode.com/problems/power-of-three/)\n```python\nclass Solution:\n    def isPowerOfThree(self, n: int) -\u003e bool:\n        return n \u003e 0 and 3 ** round(math.log(n, 3)) == n\n```\n- math.log 函数得到的数据可能不够精确，可以使用 round 取整\n## [328. Odd Even Linked List 6行](https://leetcode.com/problems/odd-even-linked-list/)\n```python\n# Definition for singly-linked list.\n# class ListNode:\n#     def __init__(self, x):\n#         self.val = x\n#         self.next = None\n\nclass Solution:\n    def oddEvenList(self, head: ListNode) -\u003e ListNode:\n        if not head or not head.next: return head\n        r, odd, p, head = head, head, head.next, head.next.next\n        while head:\n            odd.next, head.next, p.next = head, odd.next, head.next\n            p, odd, head = p.next, head, p.next and p.next.next\n        return r\n```\n- odd 记录上一个奇数位节点，p 记录前一个节点\n- 从第3个位置开始循环，每次都把当前节点接到 odd 后面，然后跳到下一个奇数位节点继续循环\n## [342. Power of Four 1行](https://leetcode.com/problems/power-of-four/)\n```python\nclass Solution:\n    def isPowerOfFour(self, num: int) -\u003e bool:\n        return num \u003e 0 and not math.log(num, 4) % 1\n```\n- 采用 log 运算，若结果为整数则 `num` 为 4 的幂\n- 整数 % 1 为 0\n## [344. Reverse String 1行](https://leetcode.com/problems/reverse-string/)\n```python\nclass Solution:\n    def reverseString(self, s: List[str]) -\u003e None:\n        \"\"\"\n        Do not return anything, modify s in-place instead.\n        \"\"\"\n        s.reverse()\n```\n## [345. Reverse Vowels of a String 2行](https://leetcode.com/problems/reverse-vowels-of-a-string/)\n```python\nclass Solution:\n    def reverseVowels(self, s: str) -\u003e str:\n        vowels = re.findall('(?i)[aeiou]', s)\n        return re.sub('(?i)[aeiou]', lambda m: vowels.pop(), s)\n```\n- 遍历俩次，第一次找出元音字母放进 stack，第二次每遇到一个就把之前的栈顶替换进来\n## [347. Top K Frequent Elements 1行](https://leetcode.com/problems/top-k-frequent-elements/)\n```python\nclass Solution:\n    def topKFrequent(self, nums: List[int], k: int) -\u003e List[int]:\n        return [*next(zip(*collections.Counter(nums).most_common(k)))]\n```\n- Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型，以字典的键值对形式存储，其中元素作为key，其计数作为value\n- 关于 Counter，更多详细内容可参考 [这里](https://www.cnblogs.com/nisen/p/6052895.html)\n- 非内置解法：\n```python\nclass Solution:\n    def topKFrequent(self, nums: List[int], k: int) -\u003e List[int]:\n        d = {n: 0 for n in nums}\n        for n in nums:\n            d[n] += 1\n        \n        r = []\n        for _ in range(k):\n            n = max(d, key=d.get)\n            r.append(n)\n            d[n] = -1\n        \n        return r\n```\n## [349. Intersection of Two Arrays 1行](https://leetcode.com/problems/intersection-of-two-arrays/)\n```python\nclass Solution:\n    def intersection(self, nums1: List[int], nums2: List[int]) -\u003e List[int]:\n        return [*set(nums1) \u0026 set(nums2)]\n```\n- 经过 set 之后，重复的元素被删除\n- 与运算对于集合来说就是求交集\n## [350. Intersection of Two Arrays II 1行](https://leetcode.com/problems/intersection-of-two-arrays-ii/)\n```python\nclass Solution:\n    def intersect(self, nums1: List[int], nums2: List[int]) -\u003e List[int]:\n        return [*(collections.Counter(nums1) \u0026 collections.Counter(nums2)).elements()]\n```\n- 对于两个 Counter 对象，与操作意味着取两者都有的key, value取小的那一个\n- 参考：[Python Counter 计数工具](https://www.cnblogs.com/nisen/p/6052895.html)\n```python\nclass Solution:\n    def intersect(self, nums1: List[int], nums2: List[int]) -\u003e List[int]:\n        nums1.sort()\n        nums2.sort()\n        r = []\n        i = j = 0\n        while i \u003c len(nums1) and j \u003c len(nums2):\n            if nums1[i] == nums2[j]:\n                r.append(nums1[i])\n                i += 1\n                j += 1\n            elif nums1[i] \u003c nums2[j]:\n                i += 1\n            else:\n                j += 1\n        return r\n```\n- 进阶解法 ↑\n- 使用双指针将两个列表中共同的元素抠下来，因为已经排序，所以遇到不同元素时数值小的那个列表的指针向前移动\n## [367. Valid Perfect Square 4行](https://leetcode.com/problems/valid-perfect-square/)\n```python\nclass Solution:\n    def isPerfectSquare(self, num: int) -\u003e bool:\n        r = num\n        while r * r \u003e num:\n            r = (r + num / r) // 2\n        return r * r == num\n```\n- 基本不等式(a+b)/2 \u003e=√ab 推导自 (a-b)^2 \u003e= 0 → a^2 + b^2 \u003e= 2ab → (a+b)/2 \u003e=√ab（换元），注意 a\u003e0 且 b\u003e0\n- `(r + num / r) / 2` \u003e= √num 而 r \u003e num / r 保证每次迭代 r 在不断减小,而`//`的存在保证最接近的时候能够逃离循环体\n## [387. First Unique Character in a String 2行](https://leetcode.com/problems/first-unique-character-in-a-string/)\n```python\nclass Solution:\n    def firstUniqChar(self, s: str) -\u003e int:\n        d = {c: s.count(c) for c in set(s)}\n        return ([i for i, c in enumerate(s) if d[c] == 1] + [-1])[0]\n```\n- 首先用字典 d 储存｛字符：出现次数｝，注意这里的字符来自 set，为了避免重复操作，防止TLE\n- 用 list 记录 s 中出现次数为 1 的字符的索引\n- 返回 list 第一个元素，如果原来的 s 中不存在出现次数为 1 的字符，则会返回后面添加的 [-1] 作为第一个元素\n## [389. Find the Difference 1行](https://leetcode.com/problems/find-the-difference/)\n```python\nclass Solution:\n    def findTheDifference(self, s: str, t: str) -\u003e str:\n        return chr(sum(map(ord, t)) - sum(map(ord, s)))\n```\n- 每一个字符都对应一个 ASCII 数字，那么那个不同的数字的 ASCII 码就等于 t 的所有字符码之和 - s 的\n- ord 函数将单个字符转换为 ASCII 码， chr相反\n## [394. Decode String 14行](https://leetcode.com/problems/decode-string/)\n```python\nclass Solution:\n    def decodeString(self, s: str) -\u003e str:\n        stack = [['', 1, '']]\n        a = n = ''\n        for c in s:\n            if c.isalpha():\n                a += c\n            elif c.isdigit():\n                n += c\n            elif c == '[':\n                stack.append([a, int(n), ''])\n                a = n = ''\n            else:\n                p, t, b = stack.pop()\n                stack[-1][-1] += p + t * (b + a)\n                a = ''\n        return stack.pop()[-1] + a\n```\n- 用 stack 记录（[]之前的字母，翻倍次数，翻倍内容）\n## [412. Fizz Buzz 1行](https://leetcode.com/problems/fizz-buzz/)\n\n```python\nclass Solution:\n    def fizzBuzz(self, n):\n        return ['Fizz' * (not i % 3) + 'Buzz' * (not i % 5) or str(i) for i in range(1, n+1)]\n```\n- 7 or 8 = 7\n- 0 or 8 = 8\n## [414. Third Maximum Number 3行](https://leetcode.com/problems/third-maximum-number/)\n```python\nclass Solution:\n    def thirdMax(self, nums: List[int]) -\u003e int:\n        nums = set(nums)\n        for _ in range((2, 0)[len(nums) \u003c 3]): nums.remove(max(nums))\n        return max(nums)\n```\n## [430. Flatten a Multilevel Doubly Linked List 5行](https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list/)\n```python\n\"\"\"\n# Definition for a Node.\nclass Node:\n    def __init__(self, val, prev, next, child):\n        self.val = val\n        self.prev = prev\n        self.next = next\n        self.child = child\n\"\"\"\nfrom itertools import chain\n\nclass Solution:\n    def flatten(self, head: 'Node') -\u003e 'Node':\n        def gen(n): yield from chain([n], gen(n.child), gen(n.next)) if n else ()\n        iters = gen(head); p = head and next(iters)\n        for n in iters: p.next, n.prev, p.child, n.child, p = n, p, None, None, n\n        return head\n```\n- 使用迭代器按顺序输出所有节点，然后连接\n## [448. Find All Numbers Disappeared in an Array 1行](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/)\n```python\nclass Solution:\n    def findDisappearedNumbers(self, nums: List[int]) -\u003e List[int]:\n        s = set(nums)\n        return [i for i in range(1, len(nums) + 1) if i not in s]\n```\n- set 的内部实现为 dict，in 操作时间复杂度为 O(1)\n- 应题目进阶要求，以下解为 O(N) 时间效率，无额外空间（除了返回数组和中间变量）\n\t```python\n\tclass Solution:\n\t    def findDisappearedNumbers(self, nums: List[int]) -\u003e List[int]:\n\t\tfor n in nums:\n\t\t    nums[abs(n) - 1] = -abs(nums[abs(n) - 1])\n\t\treturn [i + 1 for i, n in enumerate(nums) if n \u003e 0]\n\t```\n\t- 此解实际上是利用索引把数组自身当作哈希表处理\n\t- 将 nums 中所有正数作为索引i，置 nums[i] 为负值。那么，仍为正数的位置即为（未出现过）消失的数字\n\t    - 原始数组：[4,3,2,7,8,2,3,1]\n\t    - 重置后为：[-4,-3,-2,-7,`8`,`2`,-3,-1]\n\t    - 结论：[8,2] 分别对应的index为[5,6]（消失的数字）\n## [454. 4Sum II 2行](https://leetcode.com/problems/4sum-ii/)\n```python\nclass Solution:\n    def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -\u003e int:\n        dic = collections.Counter(a + b for a in A for b in B)\n        return sum(dic.get(- c - d, 0) for c in C for d in D)\n```\n- 思路同第一题 TWO SUM 的 O(N) 字典解法，记录需要的值\n## [461. Hamming Distance 1行](https://leetcode.com/problems/hamming-distance/)\n```python\nclass Solution:\n    def hammingDistance(self, x: int, y: int) -\u003e int:\n        return bin(x ^ y).count('1')\n```\n## [485. Max Consecutive Ones 1行](https://leetcode.com/problems/max-consecutive-ones/)\n```python\nclass Solution:\n    def findMaxConsecutiveOnes(self, nums: List[int]) -\u003e int:\n        return len(max(''.join(map(str, nums)).split('0')))\n```\n- 变成字符串然后用\"0\"去切分然后比子串长度\n## [494. Target Sum 5行](https://leetcode.com/problems/target-sum/)\n```python\nclass Solution:\n    def findTargetSumWays(self, nums: List[int], S: int) -\u003e int:\n        \n        def dfs(cur, i, d = {}):\n            if i \u003c len(nums) and (i, cur) not in d: # 搜索周围节点\n                d[(i, cur)] = dfs(cur + nums[i], i + 1) + dfs(cur - nums[i], i + 1)\n            return d.get((i, cur), int(cur == S))\n        \n        return dfs(0, 0)\n```\n- dfs遍历所有可能结果，以当前位置 i 和当前总和 cur 为根节点，以下一位数字的加减为邻域扩散搜索\n- 利用 d 构造记忆，以便剪枝（搜索过程中遇到相同位置和相同cur值时返回值应该相同）\n- dfs中 d 参数传的是引用，所以只有第一次会采用默认值 {}\n## [495. Teemo Attacking](https://leetcode.com/problems/teemo-attacking/)\n```python\nclass Solution:\n    def findPoisonedDuration(self, t: List[int], d: int) -\u003e int:\n        return len(t) and sum(min(t[i] - t[i-1], d) for i in range(1, len(t))) + d\n```\n- 总时间 = 所有间隔时间的总和，每一次的间隔时间 = min(下次发射时间 - 这次发射时间，duration)\n## [498. Diagonal Traverse 5行](https://leetcode.com/problems/diagonal-traverse/)\n```python\nclass Solution:\n    def findDiagonalOrder(self, matrix: List[List[int]]) -\u003e List[int]:\n        m, n, r = len(matrix), len(matrix) and len(matrix[0]), []\n        for l in range(m + n - 1):\n            temp = [matrix[i][l - i] for i in range(max(0, l+1 - n), min(l+1, m))]\n            r += temp if l % 2 else temp[::-1]\n        return r\n```\n- 0 and 0 答案是 0，此处避免 matrix 为 [] 时导致报错\n- 按照从右上角到左下角的顺序遍历 matrix 的所有对角线并放入列表 temp\n- 如果 对角线索引 l 是偶数则应该把 temp 反转\n- 把 temp 加入结果 r\n## [507. Perfect Number](https://leetcode.com/problems/perfect-number/)\n```python\nclass Solution:\n    def checkPerfectNumber(self, num: int) -\u003e bool:\n        return num in (6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128)\n```\n- 题目中给出了解的范围，且解的个数是固定的，因此可以提前计算出所有解\n## [557. Reverse Words in a String III 1行](https://leetcode.com/problems/reverse-words-in-a-string-iii/)\n```python\nclass Solution:\n    def reverseWords(self, s: str) -\u003e str:\n        return ' '.join(s.split(' ')[::-1])[::-1]\n```\n## [561. Array Partition I 1行](https://leetcode.com/problems/array-partition-i/)\n```python\nclass Solution:\n    def arrayPairSum(self, nums: List[int]) -\u003e int:\n        return sum(sorted(nums)[::2])\n```\n## [575. Distribute Candies 1行](https://leetcode.com/problems/distribute-candies/)\n```python\nclass Solution:\n    def distributeCandies(self, candies: List[int]) -\u003e int:\n        return min(len(set(candies)), len(candies) // 2)\n```\n- 姐姐优先拿不同种类的糖果\n## [581. Shortest Unsorted Continuous Subarray 2行](https://leetcode.com/problems/shortest-unsorted-continuous-subarray/)\n```python\nclass Solution:\n    def findUnsortedSubarray(self, nums: List[int]) -\u003e int:\n        diff = [i for i, (a, b) in enumerate(zip(nums, sorted(nums))) if a != b]\n        return len(diff) and max(diff) - min(diff) + 1\n```\n- 获取所有当前数组与排序后数组具有不同数值的索引，最右边的索引 - 最左边的 + 1 就是结果\n## [589. N-ary Tree Preorder Traversal 1行](https://leetcode.com/problems/n-ary-tree-preorder-traversal/)\n```python\n\"\"\"\n# Definition for a Node.\nclass Node:\n    def __init__(self, val=None, children=None):\n        self.val = val\n        self.children = children\n\"\"\"\nclass Solution:\n    def preorder(self, root: 'Node') -\u003e List[int]:\n        return root and sum([[root.val], *map(self.preorder, root.children)], []) or []\n```\n- 递归解法，利用 and or 控制递归叶节点和普通节点\n```python\n\"\"\"\n# Definition for a Node.\nclass Node:\n    def __init__(self, val=None, children):\n        self.val = val\n        self.children = children\n\"\"\"\nclass Solution:\n    def preorder(self, root: 'Node') -\u003e List[int]:\n        s = bool(root) * [root]\n        r = []\n        \n        while s:\n            root = s.pop()\n            r.append(root.val)\n            s += root.children[::-1]\n        \n        return r\n```\n- 迭代解法\n- root 为 `[]` 时 bool 值为 `False` 同 `0`，乘法结果为 `[]`，即可跳过 `while`\n- root 非空时 dfs 栈式迭代\n- 逆转 `children` 是由于栈的 `FILO(先入后出)` 特性\n\n## [599. Minimum Index Sum of Two Lists 2行](https://leetcode.com/problems/minimum-index-sum-of-two-lists/)\n```python\nclass Solution:\n    def findRestaurant(self, list1: List[str], list2: List[str]) -\u003e List[str]:\n        d = {x: list1.index(x) + list2.index(x) for x in set(list1) \u0026 set(list2)}\n        return [x for x in d if d[x] == min(d.values())]\n```\n- 使用字典记录｛共同喜欢的商店：索引和｝，返回索引和并列最小的商店名\n## [605. Can-place-flowers 2行](https://leetcode.com/problems/can-place-flowers/)\n```python\nclass Solution:\n    def canPlaceFlowers(self, flowerbed: List[int], n: int) -\u003e bool:\n        s = \"\".join(str(i) for i in [0, *flowerbed, 0]).split(\"1\")\n        return n \u003c= sum((len(i) - 1) // 2 for i in s)\n```\n- 两边都加 0, 然后按 1 分割\n## [643. 子数组最大平均数 I 2行](https://leetcode.com/problems/maximum-average-subarray-i/)\n```python\nclass Solution:\n    def findMaxAverage(self, nums: List[int], k: int) -\u003e float:\n        presum = [0, *accumulate(nums, add)]\n        return max(presum[i + 1] - presum[i + 1 - k] for i in range(k - 1, len(nums))) / float(k)\n```\n- 前缀和\n## [652. Find Duplicate Subtrees 8行](https://leetcode.com/problems/find-duplicate-subtrees/)\n```python\n# 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\nclass Solution:\n    def findDuplicateSubtrees(self, root):\n        d = collections.defaultdict(list)\n        def dfs(root):\n            if not root: return ''\n            s = ' '.join((str(root.val), dfs(root.left), dfs(root.right)))\n            d[s].append(root)\n            return s\n        dfs(root)\n        return [l[0] for l in d.values() if len(l) \u003e 1]\n```\n- 使用字典 d 记录｛子树结构：[root1，root2，……]｝\n## [658. Find K Closest Elements 2行](https://leetcode.com/problems/find-k-closest-elements/)\n```python\nclass Solution:\n    def findClosestElements(self, arr: List[int], k: int, x: int) -\u003e List[int]:\n        return sorted(heapq.nsmallest(k, arr, key=lambda n:(abs(n - x), n)))\n```\n- nsmallest 函数可以输出最小的N个数字，可参考[这里](https://www.baidu.com/link?url=6R6W8O3Ro6GQpHhQiuPUf5xvcYGSc9_8mB5lClF9-zM7kNYA1vszVmT63if0YPWPIT14W1_a_GnCPyunEW2q_yJmIYdjCqNiIlW-cp51tty\u0026wd=\u0026eqid=d729203a0001d4d8000000065d2ead3f)\n```python\nclass Solution:\n    def findClosestElements(self, arr: List[int], k: int, x: int) -\u003e List[int]:\n        l, h = 0, len(arr) - 1\n        while l \u003c h:\n            m = (l + h) // 2\n            if arr[m] \u003e= x:\n                h = m\n            else:\n                l = m + 1\n        return sorted(sorted(arr[max(0, l-k) : l+k], key=lambda y: abs(y - x))[:k])\n```\n- 二分查找法\n## [700. Search in a Binary Search Tree 1行](https://leetcode.com/problems/search-in-a-binary-search-tree/)\n```python\n# Defin","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcy69855522%2FShortest-LeetCode-Python-Solutions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcy69855522%2FShortest-LeetCode-Python-Solutions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcy69855522%2FShortest-LeetCode-Python-Solutions/lists"}