快速排序算法
(1) 快速排序法
(2) 快排前后指针
(3) 快排挖坑法
颜色分类
题目解析
参考 LeetCode 题目 颜色分类
算法原理
算法原理和移动零非常相似。
简述移动零的算法原理:
cur 在从前往后扫描的过程中,如果扫描的数符合 f 性质,就把这个数放到 dest 之前的区域;符合 g 性质则不管,直到 cur 遍历到最后,dest 指针就可以把数组划分成两个部分。
解法:三指针
当 i 遍历结束数组后,整个数组就被排好序了,并且数组以 left,right 两个指针为分界线分成三个部分。
在遍历的过程中,整个数组会被划分成四个部分:
[0, left]:存储 0(left, i):存储 1[i, right-1]:待扫描区域[right, n-1]:存储 2
对遍历到的 nums[i] 的不同元素的分类处理:
nums[i] = 0
对于这种情况,只需要 swap(nums[left + 1], nums[i]),然后 left++, i++ 即可。要注意 nums[left+1]=1。
但是有一种极端情况,就是如果 i = left + 1,并且也符合 nums[i] = 0 的情况,我们依旧要执行 swap(nums[left + 1], nums[i])。虽然这种极端情况是变成自己和自己交换,但是处理方法不变:交换完成后,left++, i++。
nums[i] = 1
此时我们令 i++ 即可。
nums[i] = 2
对于这种情况,我们可以 swap(nums[i], nums[right - 1]),然后 right--。
此时需要特别注意,swap(nums[i], nums[right - 1]) 后,i 是不可以 ++ 的,因为 [i, right-1] 是待扫描区域,交换后,nums[i] 依旧是待扫描元素,所以如果是和 right - 1 交换的情况,i 是一定不可以 ++ 的。
处理细节问题
循环终止条件
当待扫描区域已经没有元素,说明此时数组所有元素已经全部被扫描并且分好类了,结束循环即可,所以循环终止条件是 i != right。
指针初始化
根据算法原理,为了保证 left 指向 0 区域的最右边,right 区域指向 2 区域的最左边,我们交换元素是不会让 nums[left],nums[right] 亲自和 nums[i] 进行交换的。所以我们的指针初始化的值如下:
left = -1right = n这样的操作是为了避免漏掉对nums[0],nums[n - 1]的扫描。


