LeetCode075之颜色分类(相关问题:数组,双指针)

问题描述

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 01 或 2

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路分析

方法一:单指针

我们可以考虑对数组进行两次遍历。在第一次遍历中,我们将数组中所有的 0交换到数组的头部。在第二次遍历中,我们将数组中所有的 1 交换到头部的 0 之后。此时,所有的 2 都出现在数组的尾部,这样我们就完成了排序。

方法二:双指针(头头)

方法一需要进行两次遍历,那么我们是否可以仅使用一次遍历呢?我们可以额外使用一个指针,即使用两个指针分别用来交换 0 和 1。具体地,我们用指针 p0来交换 0,p1来交换 1,初始值都为 0。当我们从左向右遍历整个数组时:

  1. 如果找到了 1,那么将其与 nums[p1]进行交换,并将 p1向后移动一个位置,这与方法一是相同的;
  2. 如果找到了 0,那么将其与 nums[p0] 进行交换,并将 p0向后移动一个位置。这样做是正确的吗?
  • 我们可以注意到,因为连续的 0之后是连续的 1,因此如果我们将 0 与 nums[p0]进行交换,那么我们可能会把一个 1交换出去。当 p0

LeetCode075之颜色分类(相关问题:数组,双指针)_第1张图片

LeetCode075之颜色分类(相关问题:数组,双指针)_第2张图片

 方法三:双指针(头尾)

与方法二类似,我们也可以考虑使用指针 p0 来交换 0,p2 来交换 2。此时,p0的初始值仍然为 0,而 p2的初始值为 n-1。在遍历的过程中,我们需要找出所有的 0 交换至数组的头部,并且找出所有的 2 交换至数组的尾部。

由于此时其中一个指针 p2是从右向左移动的,因此当我们在从左向右遍历整个数组时,如果遍历到的位置超过了 p2 ,那么就可以直接停止遍历了。

具体地,我们从左向右遍历整个数组,设当前遍历到的位置为 i,对应的元素为 nums[i];

  1. 如果找到了 0,那么与前面两种方法类似,将其与 nums[p0]进行交换,并将 p0向后移动一个位置;
  2. 如果找到了 2,那么将其与 nums[p2] 进行交换,并将 p2向前移动一个位置。
  • 这样做是正确的吗?可以发现,对于第二种情况,当我们将 nums[i] 与 nums[p2]进行交换之后,新的 nums[i]可能仍然是 2,也可能是 0。然而此时我们已经结束了交换,开始遍历下一个元素 nums[i+1],不会再考虑 nums[i]了,这样我们就会得到错误的答案。

因此,当我们找到 2 时,我们需要不断地将其与 nums[p2]进行交换,直到新的 nums[i]不为 2。此时,如果 nums[i]为 0,那么对应着第一种情况;如果 nums[i]] 为 1,那么就不需要进行任何后续的操作。

LeetCode075之颜色分类(相关问题:数组,双指针)_第3张图片

代码实现

方法一:单指针

class Solution {
    public void sortColors(int[] nums) {
        int n = nums.length;
        int ptr = 0;
        for (int i = 0; i < n; ++i) {
            if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[ptr];
                nums[ptr] = temp;
                ++ptr;
            }
        }
        for (int i = ptr; i < n; ++i) {
            if (nums[i] == 1) {
                int temp = nums[i];
                nums[i] = nums[ptr];
                nums[ptr] = temp;
                ++ptr;
            }
        }
    }
}

方法二:双指针(头头)

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] == 1) {
                int temp = nums[i];
                nums[i] = nums[p1];
                nums[p1] = temp;
                ++p1;
            } else if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[p0];
                nums[p0] = temp;
                if (p0 < p1) {
                    temp = nums[i];
                    nums[i] = nums[p1];
                    nums[p1] = temp;
                }
                ++p0;
                ++p1;
            }
        }
    }
}

 方法三:双指针(头尾) 

class Solution {
    public void sortColors(int[] nums) {
        int n = nums.length;
        int p0 = 0, p2 = n - 1;
        for (int i = 0; i <= p2; ++i) {
            while (i <= p2 && nums[i] == 2) {
                int temp = nums[i];
                nums[i] = nums[p2];
                nums[p2] = temp;
                --p2;
            }
            if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[p0];
                nums[p0] = temp;
                ++p0;
            }
        }
    }
}

你可能感兴趣的:(算法,算法,数据结构)