颜色分类(双指针排序)
(对应leetcode75题)
题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
思路
利用双指针,分别指向数组的头部和尾部。因为数组中元素只有0、1、2三种情况,遍历数组,如果遍历到0,则让其与头部指针指向的元素交换位置,并且指针指向下一个元素。如果遍历到1,则直接遍历下一个元素。如果遍历到2,让其与尾部指针指向的元素交换位置,并且指针指向上一个元素(注意此时并不继续遍历下一个元素。因为如果后边的元素有1的话,那么没有交换元素,继续遍历导致2在1前面。所以只能继续遍历当前元素,尾部指针向前移动,直到交换来的元素是0或1时再向下遍历。)
代码块
class Solution {
public void sortColors(int[] nums) {
int i=0, j = nums.length - 1; //定义双指针
int count = 0; //遍历数组计数器
while(count <= j){ //当计数器超过后指针说明已将所有数字归位
if(nums[count] == 0){ //当前数字为0时和i指针数字进行交换,计数器+1
swap(nums, count, i);
i++; //i指针右移
count++;
}else if(nums[count] == 2){//当前数字为2时和j指针数字交换
swap(nums, count, j);
j--; //j指针左移
/*计数器不能+1, 若交换来的nums[count]仍是2的话,假设计数器+1, 后面的数字也都是1,这个数字2
就会卡在这里,因为此时循环已经跳出,造成结果错误,所以必须等到交换来的新nums[count]不是2(即1
或0时计数器才能+1)*/
}else{
count++;
}
}
}
public void swap(int [] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
举例
数组:[0,2,1,2,0,2,1]
1、两个指针i,j,i指向第一个元素0,j指向最后一个元素1。
2、遍历元素,计数器count = 0。第一个元素0,所以执行
if(nums[count] == 0){ //当前数字为0时和i指针数字进行交换,计数器+1
swap(nums, count, i);
i++; //i指针右移
count++;
自己跟自己交换,之后,i= 1,也就是头部指针指向第二个元素,count = 1;
3、第二个元素2,执行
else if(nums[count] == 2){//当前数字为2时和j指针数字交换
swap(nums, count, j);
j--; //j指针左移
2与最后一个元素1交换,此时count= 1,j指向倒数第二个元素2。数组变为[0,1,1,2,0,2,2]
4、仍然遍历第二个元素,是1,于是count++
5、遍历第三个元素,是1,count++
6、遍历第四个元素,是2,于是与尾部指针所指向的元素2交换,数组保持不变,但是尾部指针指向倒数第三个元素0
7、仍然遍历第四个元素,2与0交换,于是数组变为[0,1,1,0,2,2,2],第四个元素变为0,于是0与头部指针指向的第二个元素1互换,数组变为[0,0,1,1,2,2,2]
8、此时遍历到第五个元素,后指针指向倒数第四个元素,因为当计数器超过后指针,循环结束。