diff --git a/README.md b/README.md index 4b0e464..8eb4d23 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ Leet Code 刷题笔记 - - 不求最快最省,但求最短最优雅 :herb:,Shorter is better here. # 前言 -- 代码精炼是 Python 的核心,同时能够反应对于语言的熟练程度,本项目目的在于汇总 leet code 最短最优雅的解法,拒绝长篇大论,缩短学习周期,掌握各种技巧,助您在面试中写出令人眼前一亮的解答,给考官留个好印象。 -- 为什么我们追求最短?1.短代码更pythonic,而且通常能够避免一些冗余过程。2.除了刷题掌握算法思路之外,我们更追求深入理解和掌握python,学会套用技巧,举一反三。3.真正面试的时候不一定要这么短,可以适当展开几行(O_o 除非你就是想秀其他人一脸 😅),保证思路更清晰,相信就算展开几行也会比其他题解短很多吧。4.刷题很累,找点乐子,送给自己一些成就感吧。5.所有已收录代码都是优中选优,题库解析部分除了短代码外,也有常规解法作为补充。6.若基础知识不够扎实,可以先看[**专题探索**](#专题探索)部分,然后再转[**题库解析**](#题库解析)学习 Python 中隐藏的先进技巧。 - 项目持续更新中,优先使用 python3,不支持的题目使用 python2 代替,如果您有更短更优雅的解法希望分享的话欢迎联系更新~ [直接发issue 或 fork,记得留下署名和联系方式 :panda_face:] 鉴于追求的主题,此项目收录 1.在代码量(不是行数)上明显优于现有解的最短代码 2.思路更高效的一般解法(作为补充放在首选解之后) [题目自带的代码不计入代码量] - 如果您对当前解析有任何疑问,咱们 issue 见~ - 由于CSDN博客更新需要人工审核比较慢,所以迁移到github上,优先更新github内容。 @@ -23,12 +21,20 @@ - ⏱ [递归 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日 ## 推荐 +- 🐱‍👤[Python的算法题公式化套路总结](https://github.com/cy69855522/Python-Algorithm-Formula/blob/main/README.md) - 👻[ Leetcode最简C++题解 ](https://github.com/cy69855522/Simplest-LeetCode-Cpp-Solutions) - 🎃[ C++清晰题解汇总 ](https://github.com/cy69855522/Clearest-LeetCode-Cpp-Solutions) -- [🚀 AI Power](https://www.aipower.xyz) 云GPU租借/出租平台:Python是AI的核心,GPU是AI的动力,想要朝AI工程师发展的朋友不妨了解一下~ 现在注册并绑定(参考Github)即可获得高额算力,注册不涉及个人隐私信息,奖励可随时提现。详情请参考[AI Power指南](https://github.com/cy69855522/AI-Power) +- [🚀 AI Power](https://www.aipower.xyz) 云GPU租借/出租平台:Python是AI的核心,GPU是AI的动力,想要朝AI工程师发展的朋友不妨了解一下~ 现在注册并绑定(参考Github)即可获得高额算力。详情请参考[AI Power指南](https://github.com/cy69855522/AI-Power) - 🌟 推荐刷题路线:[**专题探索**](#专题探索) → [腾讯精选50题](https://leetcode-cn.com/problemset/all/?listId=ex0k24j) → [题库解析](#题库解析) +- [常用技巧总结](常用技巧总结) +- [隐藏的坑](隐藏的坑) + # 题库解析 此专栏追求代码的**精简**和**技巧性**,默认已看过题目,🤡 没看过的话点标题可以跳转链接,咱们一起体验炫酷的 Python + +
+ 点击展开折叠 + ## [1. Two Sum 4行](https://leetcode.com/problems/two-sum/) ```python class Solution: @@ -123,7 +129,7 @@ class Solution: ```python class Solution: def isPalindrome(self, x: int) -> bool: - return str(x) == str(x)[::-1] + return (k:=str(x)) == k[::-1] ``` 不使用字符串的进阶解法: @@ -250,6 +256,15 @@ class Solution: def isValid(self, s: str) -> bool: while any(('()' in s, '[]' in s, '{}' in s)): s = s.replace('()', '').replace('[]', '').replace('{}', '') return not s + +# 国际站上有一种写法是这样的,相比于上面,下面的写法更加优雅(好理解)一点 +class Solution: + def isValid(self, s: str) -> bool: + while s: + l = len(s) + s = s.replace('()', '').replace('[]', '').replace('{}', '') + if l == len(s): break + return not s ``` - 不断删除有效括号直到不能删除,思路简单效率低。另外,stack的方法也很简单,而且快多了。 @@ -258,7 +273,7 @@ class Solution: def isValid(self, s: str) -> bool: stack, d = [], {'{': '}', '[': ']', '(': ')'} for p in s: - if p in '{[(': + if p in d: stack += [p]; elif not (stack and d[stack.pop()] == p): return False @@ -499,6 +514,17 @@ class Solution: from itertools import permutations return list(permutations(nums)) ``` +## [48. rotate-image 1行](https://leetcode.com/problems/rotate-image/) +先转置后镜像对称 +```python +class Solution: + def rotate(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + matrix[:] = [i[::-1] for i in zip(*matrix)] +``` +加 [:] 才会修改原列表 ## [49. Group Anagrams 1行](https://leetcode.com/problems/group-anagrams/) ```python class Solution: @@ -991,7 +1017,7 @@ class Solution: class Solution: def singleNumber(self, nums: List[int]) -> int: from functools import reduce - return reduce(int.__xor__, nums) + return reduce(xor, nums) ``` - 这里用到了异或(xor),相同的数字异或后为0,0异或任何数都等于那个数,用reduce在列表所有元素之间使用异或^,那么留下的就是那个单独的数字了 ## [138. Copy List with Random Pointer 1行](https://leetcode.com/problems/copy-list-with-random-pointer/) @@ -1381,7 +1407,7 @@ class Solution: return int(bin(n)[2:].zfill(32)[::-1], 2) ``` - 字符串操作 -- [ziff用法](https://www.runoob.com/python/att-string-zfill.html) +- [zfill用法](https://www.runoob.com/python/att-string-zfill.html) ## [191. Number of 1 Bits 1行](https://leetcode.com/problems/number-of-1-bits/) ```python class Solution(object): @@ -1460,6 +1486,13 @@ class Solution: def isIsomorphic(self, s: str, t: str) -> bool: return [*map(s.index, s)] == [*map(t.index, t)] ``` + +```python +class Solution: + def isIsomorphic(self, s: str, t: str) -> bool: + return all(s.index(i) == t.index(j) for i,j in zip(s,t)) +``` + - 同构代表两个字符串中每个位置上字符在自身第一次出现的索引相同 ## [206. Reverse Linked List 2行](https://leetcode.com/problems/reverse-linked-list/) ```python @@ -1512,6 +1545,13 @@ class Solution: return nums[0] return f(r, k - len(l) - len(m)) ``` +```python +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + return nlargest(k,nums)[-1] +``` + +- 用了 heapq 的 nlargest 函数,返回一个 list , 然后取最后一个 ## [217. Contains Duplicate 1行](https://leetcode.com/problems/contains-duplicate/) ```python class Solution: @@ -1767,6 +1807,19 @@ class Solution: return False ``` - 从矩阵右上角开始,若值比 target 大则证明这一列的值都比 target 大,继续搜索前面的列;若比 target 小说明 target 可能在后面的行中,进入下一行 +## [242. 有效的字母异位词 1行](https://leetcode.com/problems/valid-anagram/) +```python +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return Counter(s) == Counter(t) +``` +- O(n) 思路等于建哈希表 +```python +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return sorted(s) == sorted(t) +``` +- O(n log(n)) 排序后相等,原来就相等,利用 python 的 str 可以直接排序的特点 ## [258. Add Digits 1行](https://leetcode.com/problems/add-digits/) ```python class Solution: @@ -2181,7 +2234,7 @@ class Solution: ``` - 0 and 0 答案是 0,此处避免 matrix 为 [] 时导致报错 - 按照从右上角到左下角的顺序遍历 matrix 的所有对角线并放入列表 temp -- 如果 对角线元素个数 是偶数则应该把 temp 反转 +- 如果 对角线索引 l 是偶数则应该把 temp 反转 - 把 temp 加入结果 r ## [507. Perfect Number](https://leetcode.com/problems/perfect-number/) ```python @@ -2264,6 +2317,22 @@ class Solution: return [x for x in d if d[x] == min(d.values())] ``` - 使用字典记录{共同喜欢的商店:索引和},返回索引和并列最小的商店名 +## [605. Can-place-flowers 2行](https://leetcode.com/problems/can-place-flowers/) +```python +class Solution: + def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: + s = "".join(str(i) for i in [0, *flowerbed, 0]).split("1") + return n <= sum((len(i) - 1) // 2 for i in s) +``` +- 两边都加 0, 然后按 1 分割 +## [643. 子数组最大平均数 I 2行](https://leetcode.com/problems/maximum-average-subarray-i/) +```python +class Solution: + def findMaxAverage(self, nums: List[int], k: int) -> float: + presum = [0, *accumulate(nums, add)] + return max(presum[i + 1] - presum[i + 1 - k] for i in range(k - 1, len(nums))) / float(k) +``` +- 前缀和 ## [652. Find Duplicate Subtrees 8行](https://leetcode.com/problems/find-duplicate-subtrees/) ```python # Definition for a binary tree node. @@ -2371,6 +2440,13 @@ class Solution: - 本题利用双指针,利用 i,j 双向遍历数组。 - l 记录当前索引左边所有数字之和,r 记录右边的和 - diff 记录当前索引左边所有数字之和 - 右边所有数字之和,中心索引左右和相等,diff[中心索引] 为 0 +```python +class Solution: + def pivotIndex(self, nums: List[int]) -> int: + 前缀和 = [0, *list(accumulate(nums, add))] + return next((i for i in range(len(nums)) if 前缀和[i] == 前缀和[-1] - 前缀和[i + 1]), -1) +``` +- 前缀和,利用 next 的默认值返回 -1,2 行 ## [733. Flood Fill 6行](https://leetcode.com/problems/flood-fill/) ```python class Solution: @@ -2481,6 +2557,20 @@ class Solution: def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]: return sorted(points, key=lambda x: x[0]**2 + x[1]**2)[:K] ``` +## [976. 三角形的最大周长 2行](https://leetcode.com/problems/largest-perimeter-triangle/) +```python +class Solution: + def largestPerimeter(self, A: List[int]) -> int: + A.sort(reverse=True) + return next((i+j+k for i,j,k in zip(A,A[1:],A[2:]) if j+k>i ),0) +``` +- 利用 next 函数返回第一个满足条件的值,不然就返回默认值的特点 +## [989. 数组形式的整数加法 1行](https://leetcode.com/problems/add-to-array-form-of-integer/) +```python +class Solution: + def addToArrayForm(self, A: List[int], K: int) -> List[int]: + return map(int,str(int(''.join(map(str,A)))+K)) +``` ## [1290. Convert Binary Number in a Linked List to Integer](https://leetcode.com/problems/convert-binary-number-in-a-linked-list-to-integer/) ```python # Definition for singly-linked list. @@ -2496,6 +2586,9 @@ class Solution: return r ``` - O(N), 位运算 + +
+ # 专题探索 ![](思维导图.jpg) @@ -2506,9 +2599,13 @@ class Solution: - :black_joker:【知识卡片】Python 有内置的高效**模块**实现队列/栈/优先队列:[queue模块](https://www.baidu.com/link?url=ucsY59H7zFlkJcIFNblaRqxfOmas8kRjDDro5uV3D8R2QVWWRNXWPKm2yQNAZBmOd6YGClvCsS8sZJsTTmMqGq&wd=&eqid=cbe60f050006128b000000065cd99a2e) - 栈一般使用 list 直接实现 - Python 的 collections 模块提供的[ 双向队列 collections.deque ](https://www.baidu.com/link?url=-qZCpylhJB1LQ_DMC_6eJil4g9xLaHI8IbSsHpfxG1ZEPKH_AFN8sptkOXkKqjDr0E5atG6QSLELpTSww6Z3UKnLEf0eSppKGfssCw7fq3m&wd=&eqid=821793550017be6e000000065ce99df2)同时具有 栈 和 队列 的性质,也是一个不错的选择 - + ☄ **队列:先入先出的数据结构** - :black_joker:【知识卡片】**队列**中的数据呈线性排列,就和"队列"这个名字一样,把它想象成排成一 队的人更容易理解。在队列中,处理总是从第一名开始往后进行,而新来的人只能排在队尾。像队列这种最先进去的数据最先被取来,即"先进先出"的结构,我们称为 First In First Out,简称 FIFO + +
+ 点击展开折叠 + #### [622. 设计循环队列](https://leetcode-cn.com/problems/design-circular-queue/) ```python class MyCircularQueue: @@ -2597,6 +2694,8 @@ class MyCircularQueue: ``` - 此处为体现数据结构,直接使用list,list.pop(0)耗时较多,Python 有内置的高效模块实现队列/栈/优先队列:[queue模块](https://www.baidu.com/link?url=ucsY59H7zFlkJcIFNblaRqxfOmas8kRjDDro5uV3D8R2QVWWRNXWPKm2yQNAZBmOd6YGClvCsS8sZJsTTmMqGq&wd=&eqid=cbe60f050006128b000000065cd99a2e) +
+ ☄ **队列和广度优先搜索** - :black_joker:【知识卡片】**广度优先搜索 BFS** 是一种对图进行搜索的算法。假设我们一开始位于某个顶点(即起点),此 时并不知道图的整体结构,而我们的目的是从起点开始顺着边搜索,直到到达指定顶点(即终 点)。在此过程中每走到一个顶点,就会判断一次它是否为终点。广度优先搜索会优先从离起点近的顶点开始搜索,这样由近及广的搜索方式也使得。根据 BFS 的特性,其常常被用于 `遍历` 和 `搜索最短路径` - :tophat:【套路】**BFS**一般流程: @@ -2613,6 +2712,10 @@ class MyCircularQueue: # } ``` - 使用 BFS 时,需要抓住 3 个关键点:根节点是什么?根节点的一阶邻域节点是哪些?什么时候停止搜索? + +
+ 点击展开折叠 + #### [200. 岛屿的个数](https://leetcode-cn.com/problems/number-of-islands/) ```python from queue import Queue @@ -2730,12 +2833,18 @@ class Solution: ``` - 将当前数字的总和视为节点,加上一个完全平方数后能达到的数字作为一阶邻域,搜索到达 n 的最短路径 +
+ ☄ **栈:后入先出的数据结构** - :black_joker:【知识卡片】**栈**也是一种数据呈线性排列的数据结构,不过在这种结构中,我们只能访问最新添加的数 据。栈就像是一摞书,拿到新书时我们会把它放在书堆的最上面,取书时也只能从最上面的新书开始取。Last In First Out,简称 LIFO,常常被用于数组中不同位置之间含有 `嵌套关系` 的题目 - :tophat:【套路】**栈**问题关键点: - 解决栈问题时,主要是需要确定入栈和出栈(从栈顶弹出)的条件 - 通常来说栈内储存的元素都是同一类元素,在某个层面上有共同的性质 - 嵌套关系是指出栈时得到的栈顶元素与当前判断是否入栈元素的关系,以此作为切入点套入计算题目结果所需的俩个元素是涉及栈的关键 + +
+ 点击展开折叠 + #### [155. 最小栈](https://leetcode-cn.com/problems/min-stack/solution/python-mei-ge-yi-xing-by-knifezhu/) ```python class MinStack: @@ -2822,8 +2931,14 @@ class Solution: - 使用栈储存所有未处理的数字 - 出栈时,我们总是将出栈元素与新的栈顶做运算,然后用结果更新新栈顶元素 +
+ ☄ **栈和深度优先搜索** - :black_joker:【知识卡片】**深度优先搜索 DFS** 和广度优先搜索一样,都是对图进行搜索的算法,目的也都是从起点开始搜索直到到达指定顶点(终点)。深度优先搜索会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条候补路径。正如树的遍历中所提到的,我们可以用 DFS 进行 `前序遍历`,`中序遍历` 和 `后序遍历`。在这三个遍历顺序中有一个共同的特性:除非我们到达最深的结点,否则我们永远不会回溯 + +
+ 点击展开折叠 + #### [200. 岛屿的个数](https://leetcode-cn.com/problems/number-of-islands/) ```python class Solution: @@ -2919,6 +3034,8 @@ class Solution: return r ``` +
+ ☄ **小结** - :tophat:【套路】**迭代形 BFS/DFS** ```python @@ -2944,6 +3061,10 @@ class Solution: self.dfs(node) # 递归 return image # 终止返回 ``` + +
+ 点击展开折叠 + #### [232. 用栈实现队列](https://leetcode-cn.com/problems/implement-queue-using-stacks/) ```python class MyQueue: @@ -3154,12 +3275,18 @@ class Solution: return len(seen) == len(rooms) ``` +
+ ### [🌠 数组和字符串](https://leetcode-cn.com/explore/learn/card/array-and-string/) ☄ **数组简介** - :tophat:【套路】**数组**问题必备锦囊: - 有些题目在做题之前对数组排序往往可以简化解法 - 数组与字符串大体相似但在细节上会有不同,有时候相互转化可以简化问题 + +
+ 点击展开折叠 + #### [724. 寻找数组的中心索引](https://leetcode-cn.com/problems/find-pivot-index/submissions/) ```python class Solution: @@ -3193,7 +3320,13 @@ class Solution: return list(map(int, str(int(''.join(map(str, digits))) + 1))) ``` +
+ ☄ **二维数组简介** + +
+ 点击展开折叠 + #### [498. 对角线遍历](https://leetcode-cn.com/problems/diagonal-traverse/submissions/) ```python class Solution: @@ -3231,7 +3364,13 @@ class Solution: return numRows and r or [] ``` +
+ ☄ **字符串简介** + +
+ 点击展开折叠 + #### [67. 二进制求和](https://leetcode-cn.com/problems/add-binary/submissions/) ```python class Solution: @@ -3279,6 +3418,8 @@ class Solution: return os.path.commonprefix(strs) ``` +
+ ☄ **双指针技巧** - :black_joker:【知识卡片】**双指针** 通常,我们只使用从第一个元素开始并在最后一个元素结束的一个指针来进行迭代。 但是,有时候,我们可能需要同时使用两个指针来进行迭代。 - 两个指针从 `不同位置` 出发:一个从始端开始,另一个从末端开始 @@ -3287,6 +3428,10 @@ class Solution: - 两个指针以 `不同速度` 移动:一个指针快一些,另一个指针慢一些 - 快慢指针 - 滑动窗口 + +
+ 点击展开折叠 + #### [344. 反转字符串](https://leetcode-cn.com/problems/reverse-string/solution/python-1xing-shuang-zhi-zhen-by-knifezhu/) ```python class Solution: @@ -3358,7 +3503,13 @@ class Solution: - i, j 双指针滑窗,O(N)时间复杂度,O(1)空间复杂度 - a 代表 i 到 j 的总和 +
+ ☄ **小结** + +
+ 点击展开折叠 + #### [189. 旋转数组](https://leetcode-cn.com/problems/rotate-array/) ```python class Solution: @@ -3420,10 +3571,17 @@ class Solution: nums[i] = 0 i += 1 ``` + +
+ ### [🌠 链表](https://leetcode-cn.com/explore/learn/card/linked-list/) - :black_joker:【知识卡片】链表是数据结构之一,其中的数据呈线性排列。在链表中,数据的添加和删除都较为方便, 就是访问比较耗费时间。实际上,相比较数组来说,并不存在链表这样一个对象,链表是由多个节点组成的,因此,我们能接触到的数据对象只有节点。我们可以根据节点来寻找周围节点,许多节点之间的关系抽象地构成了一个链表。 ☄ **单链表** + +
+ 点击展开折叠 + #### [707. 设计链表](https://leetcode-cn.com/problems/design-linked-list/solution/python-by-nidadianlongge/) ```python class Node: @@ -3500,7 +3658,13 @@ class MyLinkedList: ``` - 本题构建了一个双向的环形链表,记录 key 节点,key.next 指向链表的 head,key.prev 指向链表的 tail +
+ ☄ **双指针技巧** + +
+ 点击展开折叠 + #### [141. 环形链表](https://leetcode-cn.com/problems/linked-list-cycle/solution/2xing-python-by-knifezhu/) ```python # Definition for singly-linked list. @@ -3597,7 +3761,13 @@ class Solution: ``` - 列表记录整个链表,换成队列记录最后几个可以把空间复杂度压到 O(1) +
+ ☄ **经典问题** + +
+ 点击展开折叠 + #### [206. 反转链表](https://leetcode-cn.com/problems/reverse-linked-list/) ```python # Definition for singly-linked list. @@ -3677,10 +3847,22 @@ class Solution: - 首先使用快慢指针找到中点,第一个 while 停止时如果链表长度为奇数,s 为中点;否则 f 为 None,s 为右半部分的第一个节点 - 若链表长度为奇数,s 前进一步,然后 p 和 s 往俩个方向同时遍历比对是否回文 +
+ ☄ **双链表** + +
+ 点击展开折叠 + - 【设计链表】 同上 +
+ ☄ **小结** + +
+ 点击展开折叠 + #### [21. 合并两个有序链表](https://leetcode-cn.com/explore/learn/card/linked-list/197/conclusion/762/) ```python @@ -3806,10 +3988,17 @@ class Solution: return None ``` - 用 list 记录链表,把链表当作环,修补原来的切断口,创造新的缺口(k) + +
+ ### [🌠 哈希表](https://leetcode-cn.com/explore/learn/card/queue-stack/) - :black_joker:【知识卡片】在**哈希表**中,我们可以利用哈希函数快速访问到数组中的目标数据。如果发生哈希 冲突,就使用链表进行存储。这样一来,不管数据量为多少,我们都能够灵活应对。 如果数组的空间太小,使用哈希表的时候就容易发生冲突,线性查找的使用频率也会更高;反过来,如果数组的空间太大,就会出现很多空箱子,造成内存的浪费。因此, 给数组设定合适的空间非常重要。 ☄ **设计哈希表** + +
+ 点击展开折叠 + #### [705. 设计哈希集合](https://leetcode-cn.com/problems/design-hashset/) ```python class Node: @@ -3932,7 +4121,13 @@ class MyHashMap: # obj.remove(key) ``` +
+ ☄ **实际应用 - 哈希集合** + +
+ 点击展开折叠 + #### [217. 存在重复元素](https://leetcode-cn.com/problems/contains-duplicate/) ```python class Solution: @@ -3966,7 +4161,13 @@ class Solution: return n == 1 ``` +
+ ☄ **实际应用 - 哈希映射** + +
+ 点击展开折叠 + #### [1. 两数之和](https://leetcode-cn.com/problems/two-sum/) ```python class Solution: @@ -4046,7 +4247,13 @@ class Solution: - 本题题目有误,实际意思是找同数字最小间隔,若不超过 k 则满足条件 - 遍历列表,每次都比对最小间隔,并更新哈希表索引,当前位置往左的最小间隔一定是与上一次同数字出现的索引的距离 +
+ ☄ **实际应用 - 设计键** + +
+ 点击展开折叠 + #### [49. 字母异位词分组](https://leetcode-cn.com/problems/group-anagrams/) ```python class Solution: @@ -4094,7 +4301,13 @@ class Solution: ``` - 使用字典 d 记录{子树结构:[root1,root2,......]} +
+ ☄ **小结** + +
+ 点击展开折叠 + #### [771. 宝石与石头](https://leetcode-cn.com/problems/jewels-and-stones/) ```python class Solution: @@ -4201,6 +4414,9 @@ class RandomizedSet: - 插入时:用哈希表来判断是否已存在O(1),数组末尾增加一个元素O(1),哈希表记录{值:索引}O(1) - 删除时:用哈希表来定位O(1),把数组最后一个元素取下来顶替被删除元素位置O(1),更新哈希表O(1) - 取随机数时:随机从数组里面挑一个O(1) + +
+ ### [🌠 二分查找](https://leetcode-cn.com/explore/learn/card/linked-list/) - :black_joker:【知识卡片】二分查找利用已排好序的数组,每一次查找都可以将查找范围减半。查找范围内只剩一个数据时查找结束。数据量为 n 的数组,将其长度减半 log2n 次后,其中便只剩一个数据了。也就是说,在二分查找中重复执行"将目标数据和数组中间的数据进行比较后将查找范围减半"的操作 log2n 次后,就能找到目标数据(若没找到则可以得出数据不存在的结论),因此它的时间复杂度为 O(logn) - 💡【一般思路】什么时候应该使用二分搜索?怎么样使用? @@ -4253,6 +4469,10 @@ class RandomizedSet: ``` ☄ **背景** + +
+ 点击展开折叠 + #### [704. 二分查找](https://leetcode-cn.com/problems/binary-search/) ```python class Solution: @@ -4269,7 +4489,13 @@ class Solution: return -1 ``` +
+ ☄ **模板 I** + +
+ 点击展开折叠 + #### [69. x 的平方根](https://leetcode-cn.com/problems/sqrtx/comments/) ```python class Solution: @@ -4343,7 +4569,13 @@ class Solution: - 首先通过第一个二分查找得到升序排列时的开头(也就是数组中的最小值),称其为断点 k - 恢复数组后通过第二个二分查找得到目标索引 +
+ ☄ **模板 II** + +
+ 点击展开折叠 + #### [278. 第一个错误的版本](https://leetcode-cn.com/problems/first-bad-version/) ```python # The isBadVersion API is already defined for you. @@ -4414,7 +4646,13 @@ class Solution: return nums[bisect.bisect_left(self, True, 0, len(nums))] ``` +
+ ☄ **模板 III** + +
+ 点击展开折叠 + #### [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/) ```python class Solution: @@ -4481,7 +4719,13 @@ class Solution: return bisect.bisect_left(self, True, 0, len(nums)) - 1 ``` +
+ ☄ **小结** + +
+ 点击展开折叠 + #### [50. Pow(x, n)](https://leetcode-cn.com/problems/powx-n/solution/powx-n-by-leetcode/) ```python class Solution: @@ -4530,7 +4774,13 @@ class Solution: ``` - 套路B +
+ ☄ **更多练习** + +
+ 点击展开折叠 + #### [153. 寻找旋转排序数组中的最小值](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/submissions/) ```python class Solution: @@ -4618,7 +4868,13 @@ class Solution: return [i+1, j+1] ``` +
+ ☄ **更多练习 II** + +
+ 点击展开折叠 + #### [287. 寻找重复数](https://leetcode-cn.com/problems/find-the-duplicate-number/) ```python class Solution: @@ -4735,10 +4991,17 @@ class Solution: - 我们寻求的答案(最小的子数组各自和最大值)mid 被限制于一个有序的区间 [0, sum(nums)] 之内 - 向左搜索(包括 target)的条件为:nums 可以被划分为不超过 m 个和不超过 mid 的子数组 - 判断条件成立使用了贪心算法:计数 c:nums 可以被划分为至少多少个和不超过 mid 的子数组(注意如果单个数字已经超过 mid 将被单独划分,所以最后需要判断最大子数组和 r 是否满足条件) + +
+ ### [🌠 二叉树](https://leetcode-cn.com/explore/learn/card/queue-stack/) ☄ **树的遍历** ![](tree.png) + +
+ 点击展开折叠 + #### [144. 二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/) ```python # Definition for a binary tree node. @@ -4865,6 +5128,8 @@ class Solution: ``` - 使用 BFS 遍历二叉树,队列同时记录节点与层次 +
+ ☄ **运用递归解决树的问题** - 💡【一般思路】什么时候应该使用递归? - 1. 递归可以看作是四维空间中的逻辑,也就是相比普通的一个函数多了一个时间维度,当下一次的结果需要以上一次的结果作为输入时使用递归函数 @@ -4877,6 +5142,10 @@ class Solution: - :tophat:【套路】树形递归 - 树形递归类题目一般将目光集中在某个节点上,考虑节点、左子节点、右子节点之间的关系,一般递归子节点 - 通常选择一个3层完美二叉树的第2层左子节点作为参考目标,然后设计递归思路 + +
+ 点击展开折叠 + #### [104. 二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) ```python # Definition for a binary tree node. @@ -4953,7 +5222,13 @@ class Solution: - 考虑支路2:当前节点为非叶节点时将总和缩小并继续递归,判断左右节点是否存在满足条件的 - 当递归函数到达叶节点时,sum 已经被削减了多次,此时 `sum - node.val` 即为 `原始的sum - 整条路径的总和` +
+ ☄ **总结** + +
+ 点击展开折叠 + #### [106. 从中序与后序遍历序列构造二叉树](https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/comments/) ```python # Definition for a binary tree node. @@ -5140,9 +5415,16 @@ class Codec: ``` - BFS扫描,记录所有节点和他们的子节点(包括 子None) - 利用队列记录待还原节点,每次生成新节点后初始化其子节点并投入队列 + +
+ ### [🌠 二叉搜索树](https://leetcode-cn.com/explore/learn/card/introduction-to-data-structure-binary-search-tree/) ☄ **二叉搜索树简介** + +
+ 点击展开折叠 + #### [98. 验证二叉搜索树](https://leetcode-cn.com/problems/validate-binary-search-tree/) ```python # Definition for a binary tree node. @@ -5208,7 +5490,13 @@ class BSTIterator: - 空间复杂度为 O(树的高度) - 平均时间复杂度 = 循环总次数(N) / 迭代器长度(N) = O(1) +
+ ☄ **在二叉搜索树中实现搜索操作** + +
+ 点击展开折叠 + #### [700. 二叉搜索树中的搜索](https://leetcode-cn.com/problems/search-in-a-binary-search-tree/) ```python # Definition for a binary tree node. @@ -5309,7 +5597,13 @@ class Solution: - 目标只有左子或右子:用目标唯一的子节点替换目标 - 目标有左子和右子:替换目标的值为中序后继节点的值并删除后继节点 +
+ ☄ **小结** + +
+ 点击展开折叠 + #### [703. 数据流中的第K大元素](https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/) ```python class KthLargest: @@ -5372,7 +5666,13 @@ class Solution: - 因为使用了窗口,所以维护排序只需在之前已经排好序的数组 l 的基础上保持升序得插入新数字即可,这里使用二分查找搜索插入位置 - 时间复杂度为 O(Nlog(min(N, K))) 空间复杂度为 O(min(N, K)) +
+ ☄ **附录:高度平衡的二叉搜索树** + +
+ 点击展开折叠 + #### [110. 平衡二叉树](https://leetcode-cn.com/problems/balanced-binary-tree/) ```python # Definition for a binary tree node. @@ -5422,8 +5722,14 @@ class Solution: - 每次返回的根节点处于数组中间,以其左右半数组分别递归构造左右子树 - 那么就意味着左子小于根,右子大于根,且所有节点左右子树节点数相差不超过 1 (由于递归的构树方式相同,所有节点都满足高度平衡) +
+ ### [🌠 N叉树](https://leetcode-cn.com/explore/learn/card/n-ary-tree/) ☄ **遍历** + +
+ 点击展开折叠 + #### [589. N叉树的前序遍历](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/) ```python """ @@ -5498,7 +5804,13 @@ class Solution: - 使用队列 BFS 遍历 - 在队列中多保留一个层次序号记录相应层索引 +
+ ☄ **递归** + +
+ 点击展开折叠 + #### [559. N叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/) ```python """ @@ -5514,10 +5826,16 @@ class Solution: ``` - Bottom Up 递归 +
+ ## 精选 ### [🌠 递归 I](https://leetcode-cn.com/explore/learn/card/queue-stack/) ☄ **递归原理** + +
+ 点击展开折叠 + #### [344. 反转字符串](https://leetcode-cn.com/problems/reverse-string/) ```python class Solution: @@ -5550,7 +5868,13 @@ class Solution: - `seco` 指向 `head`,`head` 指向递归 `seco.next` 后返回的后序链表的头结点 - 返回新的头结点 `seco` +
+ ☄ **递推关系** + +
+ 点击展开折叠 + #### [118. 杨辉三角](https://leetcode-cn.com/problems/pascals-triangle/) ```python class Solution: @@ -5597,8 +5921,14 @@ class Solution: - 对于每一次递归,将当前节点的 `next` 属性指向前一个节点,然后递归调用下一个节点 - 如果当前节点为 `None` 则返回上一个节点,否则返回递归一下个节点的结果 +
+ ☄ **Memoization(记忆化)技术** - `递归 + 记忆` = `动态规划` + +
+ 点击展开折叠 + #### [509. 斐波那契数](https://leetcode-cn.com/problems/fibonacci-number/) ```python class Solution: @@ -5624,7 +5954,13 @@ class Solution: ``` - 到这一层的方法数 = 到前二层方法数的总和 +
+ ☄ **复杂度分析** + +
+ 点击展开折叠 + #### [104. 二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) ```python # Definition for a binary tree node. @@ -5661,7 +5997,13 @@ class Solution: - 空间复杂度:O(logN) - x^4 = x^2 ** x^2, x^5 = x^2 * x^2 * x, 借此方法可以缩减计算量 +
+ ☄ **总结** + +
+ 点击展开折叠 + #### [21. 合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/) ```python # Definition for singly-linked list. @@ -5711,6 +6053,8 @@ class Solution: - 根据二叉搜索树的特性(左子树所有节点小于根,右子树大于),可知根的左子树由比根小的数字构成,递归 `num[:i]` 就是左子树所有的可能结构,同理可获得右子树所有可能的结构 - 左右递归结果的笛卡尔积 + `root`,即为整棵树所有可能的结构 +
+ # 常用技巧总结 - set 中的 in 操作时间复杂度为 O(1) - dict.get 可以设置预设值,避免取到不存在的 key 时报错 @@ -5728,6 +6072,8 @@ class Solution: - 1 + 1 - 赋值 a - 赋值 b +- 对比两个有序列表时,我们可以通过`a,b = b,a`的方式指定`a`为第一个数字比较小的那个列表。这样可以避免使用`if`语句而重复相似的代码 +- 递归函数中为了处理特殊情况,可以在开头加一句`if ...: return ...`,而不必引入`else` # 隐藏的坑 - 遍历 set 时,输出是无序的,输出顺序可能随着计算机环境而改变 @@ -5743,3 +6089,5 @@ class Solution: - [ajin](https://github.com/ajinwu) - [grg909](https://github.com/grg909) - [Lebhoryi](https://github.com/Lebhoryi) +- [wuyudi](https://github.com/wuyudi) +- [dagongji10](https://github.com/dagongji10)

AltStyle によって変換されたページ (->オリジナル) /