原始的荷兰国旗问题是:
有n个三种颜色的小球,颜色分别为红、白、蓝,要求将这n个小球排序,使得白色在中间,红色在前面,蓝色在后面,且时间复杂度只能是 O ( N ) O(N) O(N),空间复杂度为 O ( 1 ) O(1) O(1)。
由此衍生的问题是:
给定一个数组
nums
和一个目标值target
(这个target
一定在数组中),要求使得这个数组中小于目标值的元素在左边,等于目标值的元素在中间,大于目标值的元素在右边。
思路:
定义三个指针:
less
,current
,more
,其中less
和more
分别表示小于目标值区域的右边界和大于目标值区域的左边界,初始时分别设置为-1
和N
(N
为数组长度),current
为当前遍历的索引,考虑以下几种情况:
- 若
nums[current]
<target
,说明当前值需要放置在前面,由于[0,less]
区间(可能为空)已经都是小于target
的数了,故less++
,然后交换nums[current]
和nums[less]
,然后扫描下一个数。(此处可以优化减少交换次数,当less==current
时,无需交换,current
自加即可,因为交换也是和自己交换)- 若
nums[current]>target
,首先,同理,由于[more,length-1]
区间已经都是大于target
的数了,故more--
,然后交换nums[target]
和nums[more]
,此处注意,这里由nums[more]
交换至nums[current]
的值是可能小于target
的,故此时current
是不能自加的- 若
nums[current] == target
,直接扫描下一个数即可- 退出循环的条件是什么呢?当
current
扫到more
时,说明左右都放置完成了。
对应的代码:
def partition(nums,target):
length = len(nums)
less = -1
more = length
current = 0
while current < more:
if nums[current] < target:
less += 1
if less != current:
nums[current],nums[less] = nums[less],nums[current]
current += 1
elif nums[current] > target:
more -= 1
nums[current],nums[more] = nums[more],nums[current]
# 注意此处current没有加1
else:
current += 1
return nums