Leetcode 75. 颜色分类(三指针)

  • Leetcode 75. 颜色分类(三指针)
  • 题目
    • 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
    • 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
    • 必须在不使用库内置的 sort 函数的情况下解决这个问题。
    • n == nums.length
    • 1 <= n <= 300
    • nums[i] 为 0、1 或 2
    • 你能想出一个仅使用常数空间的一趟扫描算法吗?
  • 解法
    • 三指针:建立三个指针:头指针、中指针与尾指针,中指针指向头指针前面最小远 1 的下标(如有);头指针与中指针从 0 开始往后移动,尾指针从最后一个元素开始往前移动,从头指针开始分类讨论移动指针,直到头尾指针穿过,过程如下:
      • 如果头指针元素为 0
        • 如果头中指针指向相同元素,代表头指针前全是 0,则头中指针后移
        • 如果头指针大于中指针,代表头指针(不含)到中指针全是 1,则交换头中指针,头中指针后移
        • 不会单独移动中指针,所以中指针不大于头指针
      • 如果头指针元素为 1,仅头指针后移,使头指针(不含)到中指针全是 1
      • 如果头指针元素为 2,可能将其与尾指针交换、因此需要判断尾指针元素
        • 如果尾指针元素为 0,交换头尾指针,尾指针前移,注意此处头指针不后移、因为可能头中指针间还有 1
        • 如果尾指针元素为 1,交换头尾指针,尾指针前移,此处可以结束进行下一轮循环,但是由于头指针此时一定为 1,因此还可以直接头指针后移
        • 如果尾指针元素为 2,因为尾指针后续全是2,因此仅尾指针前移
    • 移动过程中,保证头指针不小于中指针,头指针前仅有 0、1,中指针前仅有 0,头指针(不含)到中指针全是 1,尾指针后全是 2,头尾指针之间未知
  • 代码
    /**
     * 三指针:建立三个指针:头指针、中指针与尾指针,中指针指向头指针前面最小远 1 的下标(如有);头指针与中指针从 0 开始往后移动,
     * 尾指针从最后一个元素开始往前移动,从头指针开始分类讨论移动指针,直到头尾指针穿过,过程如下:
     *     如果头指针元素为 0
     *         如果头中指针指向相同元素,代表头指针前全是 0,则头中指针后移
     *         如果头指针大于中指针,代表头指针(不含)到中指针全是 1,则交换头中指针,头中指针后移
     *         不会单独移动中指针,所以中指针不大于头指针
     *     如果头指针元素为 1,仅头指针后移,使头指针(不含)到中指针全是 1
     *     如果头指针元素为 2,可能将其与尾指针交换、因此需要判断尾指针元素
     *         如果尾指针元素为 0,交换头尾指针,尾指针前移,注意此处头指针不后移、因为可能头中指针间还有 1
     *         如果尾指针元素为 1,交换头尾指针,尾指针前移,此处可以结束进行下一轮循环,但是由于头指针此时一定为 1,因此还可以直接头指针后移
     *         如果尾指针元素为 2,因为尾指针后续全是2,因此仅尾指针前移
     * 移动过程中,保证头指针不小于中指针,头指针前仅有 0、1,中指针前仅有 0,头指针(不含)到中指针全是 1,尾指针后全是 2,头尾指针之间未知
     * @param nums
     */
    private void solution(int[] nums) {
        // 判空与单个元素的特殊情况
        if (nums == null || nums.length <= 1) {
            return;
        }
        // 头指针、中指针与尾指针,中指针指向头指针前面最小远 1 的下标(如有)
        int headPoint = 0;
        int middlePoint = 0;
        int tailPoint = nums.length - 1;

        // 三指针循环数组,对每种情况分类讨论
        while (headPoint <= tailPoint) {
            if (nums[headPoint] == 0) {

                // middlePoint 不会主动后移,因此不会比 headPoint 大
                if (headPoint  == middlePoint) {

                    headPoint++;
                    middlePoint++;
                } else {

                    swap(nums, headPoint, middlePoint);
                    headPoint++;
                    middlePoint++;
                }
            } else if (nums[headPoint] == 1) {

                headPoint++;
            } else {

                if (nums[tailPoint] == 0) {

                    swap(nums, headPoint, tailPoint);
                    tailPoint--;
                } else if (nums[tailPoint] == 1) {

                    swap(nums, headPoint, tailPoint);
                    tailPoint--;
                    headPoint++;
                } else {

                    tailPoint--;
                }
            }
        }
        return;
    }

    private void swap(int[] nums, int pointA, int pointB) {
        int tmp = nums[pointA];
        nums[pointA] = nums[pointB];
        nums[pointB] = tmp;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值