思路:
方法1:先遍历一遍统计出每一个数字出现的次数,然后再遍历一遍修改nums数组。
方法2:先遍历一遍把所有的0和头部的元素交换,然后再遍历一遍把所有的1和头部之后的元素交换,最后剩下的2就在最后了。
方法3:三根指针,p0,p1用于归位0和1,i用于遍历,如果i遇到0就和p0交换,如果p0不等于p1,有可能把1交换到i的位置,需要再和p1交换一次。如果遇到1直接和p1交换就行。
方法4:三根指针,p0,p1用于归位0和1,p1和p2用于归位1和2。p1如果遇到2和结尾交换,如果p1从p2换到的可能还会继续换所以不能动。p1如果遇到0直接和开头交换,p1如果遇到1直接看下一位。
代码:
方法1:
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int cnt0 = 0, cnt1 = 0, cnt2 = 0;
for(int num : nums) {
if(num == 0) cnt0++;
else if(num == 1) cnt1++;
else cnt2++;
}
for(int i = 0; i < n; i++) {
if(i < cnt0) nums[i] = 0;
else if(i < cnt0 + cnt1) nums[i] = 1;
else nums[i] = 2;
}
}
}
方法2:
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int cur = 0;
for(int i = 0; i < n; i++) {
if(nums[i] == 0) {
nums[i] = nums[cur];
nums[cur++] = 0;
}
}
for(int i = cur; i < n; i++) {
if(nums[i] == 1) {
nums[i] = nums[cur];
nums[cur++] = 1;
}
}
}
}
方法3:
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int p0 = 0, p1 = 0;
for(int i = 0; i < n; i++) {
if(nums[i] == 0) {
nums[i] = nums[p0];
nums[p0] = 0;
if(p0 < p1) {
int t = nums[p1];
nums[p1] = nums[i];
nums[i] = t;
}
p0++;
p1++;
}
else if(nums[i] == 1) {
nums[i] = nums[p1];
nums[p1] = 1;
p1++;
}
}
}
}
方法4:
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int p0 = 0, p1 = 0, p2 = n - 1;
while(p1 <= p2) {
if(nums[p1] == 0) {
nums[p1] = nums[p0];
nums[p0] = 0;
p0++;
p1++;
}
else if(nums[p1] == 2) {
nums[p1] = nums[p2];
nums[p2] = 2;
p2--;
}
else {
p1++;
}
}
}
}
参考:
Q&A:
1 方法3的代码中p0 < p1 的时候交换怎么理解?
首先明确p0\p1的含义,这里以p0为例,p0表示等待换为0的位置,并且p0之前全是0,但p0不是0。同理,p1表示等待换为1的位置,并且p1之前是已经排好的0和1。
因为最终的答案中00000111111,0一定是在1的左边的,所以p0也一定是在p1的左边的,也可以相等,相等的时候表示还没有出现1,之前全是0,不相等的时候,为了符合p0的含义,p0的位置一定是1,所以要额外再和p1交换一次。