给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色
解法:
三路归并,其实也是 Arrays.sort() 这里采用的方法,也是三色旗的解决方案。
三个指针,分别是 left、cur、right。left指向数组最左侧,right指向数组最右侧,cur代表当前正在遍历的数组元素,当 cur 遍历的元素是 0 时,将 cur 指向的元素 与 p0 指向的元素交换,然后 cur++,p0++。当 cur 遍历的元素是 1 时,cur++。当 cur 遍历的元素是 2 时,将 cur 指向的元素与 p2 指向的元素交换,然后 p2–,cur不动!!!直到 cur > p2 ,循环结束(即全部扫描完毕)。
对于以上,有一个难点!为何 cur 在于 p0 交换时需要 p0++,cur++;而在 cur 与 p2 交换时,却只需要 p2++?
对于上面这个问题,有两种解释思路:1.cur 与 p0 交换需要自加,是因为其左边已经扫描过了,交换过来的值也是之前就扫描过了的,而右边不是, p2 交换过来的值 cur 并没有扫描过;2.当 cur 与 p0 不是一个指向同一个索引值时,那 cur 指向的索引值如果发生交换,那交换过来的一定是 1(原因是只有当遍历过的节点有1,p0 和 cur 才不会同步),而 如果索引是 1 刚好也就不用有任何操作,所以可以直接继续向右扫描,当 cur 和 p0 指向的是同一个索引,那交换就等于没交换,故也是直接可以向右扫描,右边的就不行。
#75 排序,不使用额外空间
def sord_colors(nums):
n = len(nums)
if n <= 1:
return nums
left_index,right_index = 0,n-1
cur_index = 0
while cur_index<=right_index:
if nums[cur_index] == 0:
nums[cur_index],nums[left_index] = nums[left_index],nums[cur_index]
left_index += 1
cur_index += 1 #这里需要加一是因为:cur_index左边的元素已经遍历过了,所以交换之后的这个元素是已经判断过的,所以不需要在判断了
elif nums[cur_index] == 2:
nums[cur_index],nums[right_index] = nums[right_index],nums[cur_index]
right_index -= 1#这里没有把cur_index加1是因为:cur_index右边的元素还没有哦判断,所以交换之后的元素还需要在判断一下
else:
cur_index += 1
return nums
nums = [2,0,2,1,1,0]
sord_colors(nums) #Out[28]: [0, 0, 1, 1, 2, 2]