LeetCode刷题指南
第 0 章 hot100
0.1 哈希
0.2 双指针
0.3 滑动窗口
0.4 子串
0.5 普通数组
0.6 矩阵
0.7 链表
0.8 二叉树
0.9 图论
0.10 回溯
0.11 二分查找
0.12 栈
0.13 堆
0.14 贪心算法
0.15 动态规划
0.16 多维动态规划
0.17 技巧
第0-1章 面试经典150
0.1 数组/字符串
0.2 双指针
0.3 滑动窗口
链表
二叉树
第 1 章 最易懂的贪心算法
1.1 算法解释
1.2 分配问题
1.3 区间问题
1.4 练习
第 2 章 玩转双指针
2.1 算法解释
2.2 Two Sum
2.3 归并两个有序数组
2.4 滑动窗口
2.5 快慢指针
2.6 练习
第 3 章 居合斩!二分查找
3.1 算法解释
3.2 求开方
3.3 查找区间
3.4 查找峰值
3.5 旋转数组查找数字
3.6 练习
第 4 章 千奇百怪的排序算法
4.1 常用排序算法
4.2 快速选择
4.3 桶排序
4.4 练习
第 5 章 一切皆可搜索
5.1 算法解释
5.2 深度优先搜索
5.3 回溯法
5.4 广度优先搜索
5.5 练习
第 6 章 深入浅出动态规划
6.1 算法解释
6.2 基本动态规划:一维
6.3 基本动态规划:二维
6.4 分割类型题
6.5 子序列问题
6.6 背包问题
6.7 字符串编辑
6.8 股票交易
6.9 练习
第 7 章 化繁为简的分治法
7.1 算法解释
7.2 表达式问题
7.3 练习
第 8 章 巧解数学问题
8.1 引言
8.2 公倍数与公因数
8.3 质数
8.4 数字处理
8.5 随机与取样
8.6 练习
第 9 章 神奇的位运算
9.1 常用技巧
9.2 位运算基础问题
9.3 二进制特性
9.4 练习
第 10 章 妙用数据结构
10.1 C++ STL
10.2 Python 常用数据结构
10.3 数组
10.4 栈和队列
10.5 单调栈
10.6 优先队列
10.7 双端队列
10.8 哈希表
10.9 多重集合和映射
10.10 前缀和与积分图
10.11 练习
第 11 章 令人头大的字符串
11.1 引言
11.2 字符串比较
11.3 字符串理解
11.4 字符串匹配
11.5 练习
第 12 章 指针三剑客之一:链表
12.1 数据结构介绍
12.2 链表的基本操作
12.3 其它链表技巧
12.4 练习
第 13 章 指针三剑客之二:树
13.1 数据结构介绍
13.2 树的递归
13.3 层次遍历
13.4 前中后序遍历
13.5 二叉查找树
13.6 字典树
13.7 练习
第 14 章 指针三剑客之三:图
14.1 数据结构介绍
14.2 二分图
14.3 拓扑排序
14.4 练习
第 15 章 更加复杂的数据结构
15.1 引言
15.2 并查集
15.3 复合数据结构
15.4 练习
第16章 面试题
第 17 章 十大经典排序算法
README
本文档使用 MrDoc 发布
-
+
首页
4.1 常用排序算法
# 4.1 常用排序算法 虽然在 C++ 和 Python 里都可以通过 sort 函数排序,而且刷题时很少需要自己手写排序算法,但是熟习各种排序算法可以加深自己对算法的基本理解,以及解出由这些排序算法引申出来的题目。这里我们展示两种复杂度为 $O(n \log n)$ 的排序算法:`快速排序`和`归并排序`,其中前者实际速度较快,后者可以保证相同值的元素在数组中的相对位置不变(即“稳定排序”)。 ## 快速排序(Quicksort) 快速排序的原理并不复杂:对于当前一个未排序片段,我们先随机选择一个位置当作中枢点,然后通过遍历操作,将所有比中枢点小的数字移动到其左侧,再将所有比中枢点大的数字移动到其右侧。操作完成后,我们再次对中枢点左右侧的片段再次进行快速排序即可。可证明,如果中枢点选取是随机的,那么该算法的平均复杂度可以达到 $O(n \log n)$,最差情况下复杂度则为 $O(n^2)$。 我们采用左闭右闭的二分写法,初始化条件为 $l =0,r =n − 1$。 ```py def quickSort(nums: List[int], l: int, r: int) -> bool: if l >= r: return # 在当前的[l, r]区间中,随机选择一个位置当作pivot。 pivot = random.randint(l, r) pivot_val = nums[pivot] # 将pivot与l交换。 nums[l], nums[pivot] = nums[pivot], nums[l] # 从[l+1, r]两端向内遍历,查找是否有位置不满足递增关系。 i, j = l + 1, r while True: while i < j and nums[j] >= pivot_val: j -= 1 while i < j and nums[i] <= pivot_val: i += 1 if i == j: break # i位置的值大于pivot值,j位置的值小于pivot值,将二者交换。 nums[i], nums[j] = nums[j], nums[i] # i和j相遇的位置即为新的pivot,我们将pivot与l重新换回来。 # 此时相遇位置左侧一定比pivot值小,右侧一定比pivot值大。 new_pivot = i if nums[i] <= nums[l] else i - 1 nums[l], nums[new_pivot] = nums[new_pivot], nums[l] quickSort(nums, l, new_pivot - 1) quickSort(nums, new_pivot + 1, r) ``` ## 归并排序(Merge Sort) 归并排序是典型的分治法,我们在之后的章节会展开讲解。简单来讲,对于一个未排序片段,我们可以先分别排序其左半侧和右半侧,然后将两侧重新组合(“治”);排序每个半侧时可以通过递归再次把它切分成两侧(“分”)。 我们采用左闭右闭的二分写法,初始化条件为 $l =0,r = n − 1$,另外提前建立一个和 nums 大小相同的数组 cache,用来存储临时结果。 ```py def mergeSort(nums: List[int], cache: List[int], l: int, r: int) -> bool: if l >= r: return # 分。 mid = (l + r) // 2 mergeSort(nums, cache, l, mid) mergeSort(nums, cache, mid + 1, r) # 治。 # i和j同时向右前进,i的范围是[l, mid],j的范围是[mid+1, r]。 i, j = l, mid + 1 for pos in range(l, r + 1): if j > r or (i <= mid and nums[i] <= nums[j]): cache[pos] = nums[i] i += 1 else: cache[pos] = nums[j] j += 1 nums[l:r+1] = cache[l:r+1] ```
嘉心糖糖
2025年3月11日 19:00
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码