(一)给定数组arr和一个数num,要求将数组中小于等于num的数放在数组左边,大于num的数放在数组右边(左部分和右部分内部无需有序)。并需要满足额外空间复杂度O(1),时间复杂度O(N)。
思路:首先可以假定一个“小于等于区域”,用一个变量记录这个区域的边界,初始状态是“小于等于区域”不包括任何数,位于数组左侧之外。然后用另一个变量i记录位置。那么可以分为两种情况:
(1)arr[i] <= num ——> 当前数和“小于等于区域”的下一个数交换,“小于等于区域”向右扩一位,当前数跳至下一个;
(2) arr[i] > num ——> 当前数直接跳下一个
也就是在遍历的过程中已经拉出了区间,使得满足题目要求。用了有限几个变量,因此额外空间复杂度是O(1),只需要遍历一次,满足时间复杂度O(N)的要求。
(二)荷兰国旗问题
给定数组arr和一个数num,要求将小于num的数放在数组左边,等于num的数放在数组中间,大于num的数放在数组右边。并需要满足额外空间复杂度O(1),时间复杂度O(N)。
思路:和上面的问题类似,只不过要假定一个“小于区域”和一个“大于区域”。设想初始状态下“小于区域”在数组的左侧之外,“大于区域”在数组的右侧之外,都未包含任意数。同样需要变量i记录位置,那么可以分为三种情况:
(1)arr[i] < num ——> 当前数和“小于区域”的下一个数交换,“小于区域”向右扩一个位置,当前数跳至下一个;
(2)arr[i] = num ——>当前数直接跳至下一个
(3) arr[i] > num ——> 当前数与“大于区域”前一个数交换,“大于区域”向左扩一位,当前数定在原地不变(因为交换过后的数还未比较判断)。
Java
1 | public static int[] partition(int[] arr, int left, int right, int num) { |
JavaScript
1 | function partition(arr, left, right, num){ |
(三)原始快速排序
将数组的最后一个值作为荷兰国旗问题中的num,然后通过该问题的思路将数组分为三部分:左侧< num;中间== num,右侧>num;然后递归执行左侧和右侧部分。
当num越靠近两侧时,时间复杂度越高,越靠近中间时,时间复杂度越低。此版本的快速排序时间复杂度为O(N^2)。
(四)随机快速排序(改进版)
在数组中随机选择一个数作为num,同样将数组分为三部分:左侧< num;中间== num,右侧>num;然后递归执行左侧和右侧部分。时间复杂度为O(N×logN)。快排的空间复杂度是O(logN),在有利情况中,随机选取的数的位置接近中点,此时空间复杂度O(logN),如果偏离中点较多,那么空间复杂度为O(N),最终按概率收敛到O(logN)。和时间复杂度的计算类似,都是与概率相关的计算,是一个长期期望的值。
Java
1 | public static void quickSort(int[] arr) { |
JavaScript
1 | function quickSort(arr){ |