LeetCode精选100题(4)——颜色分类

前言

  LeetCode精选100题系列第四题。

题目

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

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

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

解题方法

方法一:单指针

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

  具体地,我们使用一个指针 ptr 表示「头部」的范围,ptr 中存储了一个整数,表示数组 nums 从位置 0 到位置 ptr−1 都属于「头部」。ptr 的初始值为 0,表示还没有数处于「头部」。
在第一次遍历中,我们从左向右遍历整个数组,如果找到了 0,那么就需要将 0 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 0 都被交换到「头部」的范围,并且「头部」只包含 0。

  在第二次遍历中,我们从「头部」开始,从左向右遍历整个数组,如果找到了 1,那么就需要将 1 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 1 都被交换到「头部」的范围,并且都在 0 之后,此时 2 只出现在「头部」之外的位置,因此排序完成。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        ptr = 0
        for i in range(n):
            if nums[i] == 0:
                nums[i], nums[ptr] = nums[ptr], nums[i]
                ptr += 1
        for i in range(ptr, n):
            if nums[i] == 1:
                nums[i], nums[ptr] = nums[ptr], nums[i]
                ptr += 1

方法二:双指针

  我们可以考虑使用指针 p0来交换 0,p2来交换 2。此时,p0的初始值仍然为 0,而 p2的初始值为 n−1。在遍历的过程中,我们需要找出所有的 0 交换至数组的头部,并且找出所有的 2 交换至数组的尾部。由于此时其中一个指针 p2是从右向左移动的,因此当我们在从左向右遍历整个数组时,如果遍历到的位置超过了 p2,那么就可以直接停止遍历了。
  具体地,我们从左向右遍历整个数组,设当前遍历到的位置为 i,对应的元素为 nums[i];如果找到了 0,那么与前面两种方法类似,将其与 nums[p0] 进行交换,并将 p0向后移动一个位置;如果找到了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,那么就不需要进行任何后续的操作。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        p0, p2 = 0, n - 1
        i = 0
        while i <= p2:
            while i <= p2 and nums[i] == 2:
                nums[i], nums[p2] = nums[p2], nums[i]
                p2 -= 1
            if nums[i] == 0:
                nums[i], nums[p0] = nums[p0], nums[i]
                p0 += 1
            i += 1

拓展

  题目要求对三种颜色分类,我们很容易拓展到N中颜色分类,此时方法二就不适用了,但我们仍然可以使用方法一。遍历N-1次,每次排序好一种颜色。所以方法一更具有普适性,需要掌握。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值