
这题是典型的荷兰国旗问题,最初由 Edsger W. Dijkstra提出。
三路快排 :与双路快排的不同是,它每次挑选出枢纽元素后,不是将数组分为小于等于枢纽元素,大于枢纽元素两部分,而是分成小于枢纽元素,等于枢纽元素,大于枢纽元素三部分,然后再对大于枢纽元素和小于枢纽元素这两个子序列进行上述操作。
三路快排代码
这里借助三路快排的思路,一次遍历就可以将荷兰国旗问题解决。
思路
我们定义三个区间[0, p0), [p0, p2], (p2, n-1],表示排序后0,1,2的三个区间。
所以p0表示0的右边界,p2表示2的左边界,我们再定义cur表示当前元素
遍历步骤如下:
nums[cur]==0,则swap(nums[cur],nums[p0]),同时cur++;p0++nums[cur]==1,则直接cur++nums[cur]==2,则swap(nums[cur],nums[p2]),同时只有p2--
很好理解,就是当前元素是0,就把它放到左边0的区间中,同时0的区间右端点更新;当前元素是1,直接省略掉;当前元素时2,就把它放到右边的2的区间中,同时区间左端点更新。
可是,为什么当前元素是0,cur和p0都要更新;但当前元素是2,则只有p2更新呢?
这个是由于当前元素是0时,不管是nums[cur], 还是nums[p0],都检查过了;但是当前元素是2时,nums[p2]是还没有进行检查的元素,如果交换后cur++,就把该元素忽略掉了。
不理解的话自己可以手推一个例子看一下
Python代码
def sortColors(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""p0, p2, cur = 0, len(nums)-1, 0while cur <= p2:if nums[cur] == 0:nums[cur], nums[p0] = nums[p0], nums[cur]p0 += 1cur += 1elif nums[cur] == 2:nums[cur], nums[p2] = nums[p2], nums[cur]p2 -= 1else:cur += 1
这个题用常规快排也可以解决,只不过需要遍历两次,不过时间复杂度也是O(n)
def sortColors(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""def Partition(low, high, pivlot):temp = nums[low]while low < high:while low < high and nums[high] > pivlot:high -= 1nums[low] = nums[high]while low < high and nums[low] <= pivlot:low += 1nums[high] = nums[low]nums[low] = temp# 使用快排的思路,两遍即可# 第一遍,排好0,第二遍,排好1,时间复杂度为O(2*n)=O(n)# 第一遍,排好0l, h = 0, len(nums)-1while l <= h and nums[l] == 0:l += 1if l < h:Partition(l, h, 0)# 第二遍,排好1l = 0while l <= h and nums[l] <= 1:l += 1if l < h:Partition(l, h, 1)
